[plt-scheme] keywords (a backward-incompatible change)

From: Eli Barzilay (eli at barzilay.org)
Date: Sat Oct 1 20:21:26 EDT 2005

On Oct  1, Jim Blandy wrote:
> How do you distinguish a keyword passed as a value from one being
> used to identify a keyword argument?

Using the standard hack -- which means that there is no way to
distinguish them...

> You haven't given examples of the syntax used for calling procedures
> with keyword arguments. [...]

The change to MzScheme is just the fact that keyword arguments are
added.  Actually using them is left for a library -- and the current
plan is to take the Swindle thing and make it into a mzlib library.
The docs for Swindle should explain what that will do, roughly.  Since
this will be done in Scheme, then changing it is going to be easier,
and the effect would be noticeable only when you want to use that

One thing that Swindle can do, which does not follow CL, is that it
can use a style where you can have

  (fun :key1 val1 :key2 val2
       other args ...)

See the description of &body in the Swindle docs (which is the only CL
&keyword that is treated differently).  This is the feature that will
make slideshow much easier, since you will get

  (slide :center? #t :tall? #t
         contents ...)

> Would the following code be equivalent?
>    (let ((x :equal))
>      (member 'a '(a b c) x y))

Yes -- except that there is no plan on changing core functionality to
use keywords, certainly not the CL thing of a generic member with a
keyword that determines which variant to use at compile time.
(Personally I think that these things are cute, but the current plan
is to just get some functionality in.)

> If so, that's really gross.  You can't tell from looking at a call
> whether it's being passed keyword arguments or not.  How do you
> statically type calls like that?  And it makes using things like
> 'apply' treacherous: keywords appearing in the data can change the way
> the argument list's elements get interpreted.

FWIW, this is what CL does:

  (let ((key :test) (x #'equal)) (member '(1) '((1) (2) (3)) key x))

does what you think it will do.

> I'm not sure how to get around this.  The ideal behavior would be
> for keywords to affect argument passing only when they appear
> directly in the call expression.  When an argument's value is a
> keyword object, that argument should be passed as a positional
> parameter, like anything else.  So, the second expression above
> would simply call member with four positional arguments.

This would be the OCaml way, I think.  It sounds like a more sane
approach if core functions will use keywords.  It has another
advantage, the fact that you can eliminate run-time costs completely,
but this comes at a price of being less flexible -- for example, there
will be no way to do something like:

  (define (my-slide . args) (apply slide :tall? #t args))

But since it has its uses, then perhaps it will be a nice alternative
library (or maybe just add it to the same one, if it will make sense).
Actually, using this approach it makes sense to have a sequence of
keyword-values, and then a rest argument.

> Another concern: if you use variadic lambdas and case-lambdas as the
> underlying implementation mechanism, then that would mean that any
> function that takes keyword arguments would have an at-least-n style
> arity.  You lose information.

Yes, doing the flexible CLish thing means that arity information is
lost.  The rigid compile-time keyword thing might allow something, but
I'm not sure how that will look like, and if it will be added in this
library or not.  (Depends on hacking time.)

          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                  http://www.barzilay.org/                 Maze is Life!

Posted on the users mailing list.