|Here's an old favorite of mine (http://arclanguage.org/item?id=10692):|
In vanilla arc you'd have to specify all optionals if you wanted to give a body, which sucks.
(mac paginate(url numitems ? nextcopy "next" prevcopy "prev" . body)
`(withs (start-index (arg req "from")
end-index (+ start-index ,numitems))
(nav ,url start-index end-index)))
With keyword args (http://arclanguage.org/item?id=12657) I can now say:
Much better. But I've started to notice that when macros have both optionals and body args the body is rarely unspecified. It seems unfortunate to need the keyword arg for the common case.
(paginate "/foo" 10
My first solution was to make :do a synonym for :body. Still the extra token, but somehow I don't notice it as much. It also reduced my hankering for racket's fully-flexible keyword args (http://arclanguage.org/item?id=12944).
Now I realize that you can indeed eliminate the extra token: just make rest args take precedence over optional args. In wart (http://github.com/akkartik/wart) I can now say:
Rest args are now greedy and eager; anything left over after required args goes to them. To add optional args you have to explicitly specify keywords:
(paginate "/foo" 10
..) ; body
Behavior in the absence of rest args should not change.
(paginate "/foo" 10 :nextcopy "newer →" :prevcopy "← older"
 Credit goes primarily to evanrmurphy, for resurfacing the design of optional args (http://arclanguage.org/item?id=13029), and for the idea of making all variables optional (http://arclanguage.org/item?id=13030). When I thought of creating a new category of lazy optionals (http://arclanguage.org/item?id=13056) I realized I already have two kinds of optionals; I never bothered adding any error checking to my parsing and wasn't actually checking that functions got all their required args :) Optionals were providing merely the ability to provide a different default value. Now they're pulling more weight.
Here's my current definition of updating, with example uses:
(mac updating(place ? with t unless 'iso . body)
`(let ,rhs ,with
(unless (,unless ,place ,rhs)
(= ,place ,rhs)
(mac firsttime(place . body)
(updating (uvar u last-login) :with (date) ; extra token; seems useful
(ret max 0
(each elem '(1 3 2 6 5)
(updating max :with elem :unless >=
(prn "max now: " max))))