...the reason it returns nil is I think because (car nil) in arc is nil. I think this is the Right Thing overall, even though an empty list doesn't really have a car.
However, in the case of parameter destructuring we could do better, because during destructuring we could (if it worked this way) supply default optional values to have more intelligent handling if a part of a destructuring encounters an empty list and "runs out" of values to destructure. It would look like this:
arc> (def foo (((o a 'falafel) . b))
a)
#<procedure: foo>
arc> (foo '(bar baz))
bar
arc>(foo nil)
falafel
The value of this would be:
1. List processing functions, among others, could tell when they run out of values for destructuring by checking for the magic optional value
2. It might be possible to get this behavior "for free" without growing the source of arc, since it seems like it might just be a generalization of current destructuring/optional support.
Hmm. A quick check in the arc interpreter reveals that (car nil) and (cdr nil) are both nil, so you're right about that.
However, there could be another reason this is working. In your particular example, the full expanded version of the function call is
(foo . (nil . nil)),
or in other words,
(cons foo
(cons nil
nil)).
So it really should be destructuring that way anyway.
Now, having said that, can anyone give a good reason that (car nil) and (cdr nil) are nil? It seems a little strange to me, although I can see that it helps destructuring.