Skip to content

Latest commit

 

History

History
106 lines (92 loc) · 3.85 KB

README.md

File metadata and controls

106 lines (92 loc) · 3.85 KB

define2

Provides new but backward-compatible[*] definitions of lambda and define that simplify keyword arguments and designing wrapper functions. Also features compile-time checking of the number of arguments and the keyword names in function calls. See the [docs]

The keywords #:! for mandatory keyword arguments and #:? for optional keyword arguments are special keywords. For example:

(define (foo #:! an-argument #:? [some-other-argument 3])
  ...)

is equivalent to

(define (foo #:an-argument an-argument #:some-other-argument [some-other-argument 3])
  ...)

In both cases above, a call to foo is written

(foo #:an-argument ... #:some-other-argument ...)

Furthermore (and that was the original intent of this package), designing wrapper functions is greatly simplified:

#lang racket
(require define2)

; First let's define a function with an optional keyword that has a default value,
; and one mandatory argument:
(define (foo #:? [x 3] #:! y)
  (+ x y))

; Now let's define a wrapper function `foo2` that merely calls `foo` but specifies 
; a value for `y` while keeping the default value for `x`—whichever value this is:
(define (foo2 #:? x)
  (foo #:x x #:y 1))

(foo2) ; 4
(foo2 #:x 0) ; 1

[*] Unless the original code uses one of the special keywords #:! or the #:?. Note that (define (foo #:x xx) ...) is still a valid definition with define2.

Wrappers

Have you ever tried to write a simpler wrapper function for a function with several optional arguments, but eventually quitted because it was so ugly? Say, you really just wanted to set x-min to 0 by default instead of #f in plot...

In plain Racket, you would have to write it like this:

(define (my-plot renderer-tree
                 #:x-min [x-min 0]
                 #:x-max [x-max #f]
                 #:y-min [y-min #f]
                 #:y-max [y-max #f]
                 #:width [width (plot-width)]
                 #:height [height (plot-height)]
                 #:title [title (plot-title)]
                 #:x-label [x-label (plot-x-label)]
                 #:y-label [y-label (plot-y-label)]
                 #:legend-anchor [legend-anchor (plot-legend-anchor)]
                 #:out-file [out-file #f]
                 #:out-kind [out-kind 'auto]
                 )
  (plot renderer-tree
        #:x-min x-min
        #:x-max x-max
        #:y-min y-min
        #:y-max y-max
        #:width width
        #:height height
        #:title title
        #:x-label x-label
        #:y-label y-label
        #:legend-anchor legend-anchor
        #:out-file out-file
        #:out-kind out-kind))

Not only does this require you to know all the default values, but every optional name is written 4 times... That's really not worth it for a mere #:xmin [x-min 0]!

But suppose that plot had been defined using define2 instead with optional arguments with #:?, then we would just have to use the new define-wrapper form and write

(define-wrapper (my-plot (plot renderer-tree
                               #:? [x-min 0]
                               #:? x-max
                               #:? y-min
                               #:? y-max
                               #:? width
                               #:? height
                               #:? title
                               #:? x-label
                               #:? y-label
                               #:? legend-anchor
                               #:? out-file
                               #:? out-kind)))

which is certainly more bearable, and doesn't require to know the actual default values. See some more options in the docs.