(a b (c d)) ; destructured
(a b '(c 3) 'd) ; optional args
The quotes are only required to resolve ambiguity.
(a b (c 3) (d nil)) ; optional args - defaults aren't variables
(a b '(c A) '(d) ; needs quote to disambiguate from destructuring
b) Quote destructured args to distinguish them from optional args.
(a b '(c d)) ; destructured
(a b (c 3) (d)) ; optional args
Unlike the previous case you'll never be able to drop the quotes. But you'll rarely need more than one.
c) Use dot to delimit optional args from required ones. So arg lists could now have 3 different zones: required/destructured args, optional, and rest/body args.
(a b . c d) ; optional args since you can only have one rest arg
(a b . c) ; rest args
(a b . (c)) ; c is optional - rest args will never be destructured.
(a b . (c 3) (d 4) . e) ; optional args with defaults and a rest arg.
The dot delimiter for optional args is only needed for disambiguation, so this is equally clear:
I dunno. It seems I'm in the minority, but I actually like using (o arg default). Only problem is the whole "don't use o when destructuring" thing, which is annoying. As for these options, I agree with conanite. In general, overloading either quotes or dots would be weird.
You could tweak o to be nicer to multiple parameters, though. E.g.,
(def trim (s (o where 'both) (o test whitec))
If CL's &optional came to this forum it would say: If you're going to have a new keyword like o, at least take advantage of the fact that required args can't follow optional args, and get rid of the parens.
I like how you argue this is a rare case :) My motivation is purely aesthetic, under the assumption that I'll want to make a long term commitment to a 100-year language something like arc. I'm trying to add keyword arguments to arc, and I figure I might as well revisit this decision at the same time.
Two problems with (o arg default) - you need to remember not to use 'o at the start of a destructuring list (and not get confused when you see (def handle-request ((i o ip)) ...) ), and as akkartik says it's paren-inefficient, a single keyword to delimit required/optional args would mean fewer tokens.
The first problem is easy to fix though - use a symbol that's less likely to be an arg name to identify optional args. How about '= ?
(def myfun (a b (= c (something)) ...)
it has the advantage of similarity with ruby:
def myfun a, b, c=something
disadvantage: looks silly when you don't supply a default value:
Thinking about the paired-o suggestion I made, it has an advantage over grouping single optional arguments by their own parens -- at least if you have more than 2 optional parameters :). Compare:
(a b (opt-c default-c))
(a b (o opt-c default-c))
(a b (opt-c default-c) (opt-d default-d))
(a b (o opt-c default-c opt-d default-d))
(a b (opt-c default-c) (opt-d default-d) (opt-e default-e))
(a b (o opt-c default-c opt-d default-d opt-e default-e))
It's like a 3-character &optional, just with one of the characters at the end. However, you'd need to specify nil defaults by hand (though you might let an uneven pair at the end default to nil). E.g.,
(def markdown (s (o maxurl) (o nolinks))
could, at best, become
(def markdown (s (o maxurl nil nolinks))
But paired-o also generalizes the current behavior, so we could still use the original signature.