Am Di., 3. März 2020 um 14:19 Uhr schrieb Lassi Kortela <>:
> I think we should make a distinction between the API thar R7RS-large
> will provide and the extensibility of the language by the users.
> While for the R7RS-large API, the default value of #f will just be fine
> and will ease programming with the provided libraries, this does not
> necessarily mean that we have to prevent users from providing non-"#f"
> defaults in their own libraries.

You can always give your own "real default value" using let:

(define/kw (download url (scheme port))
   (let* ((scheme (or scheme (url-scheme url) "http"))
          (port   (or port (default-port scheme))))

and indeed, people do it all the time in systems like Emacs.

The only real difference is when you need to define a procedure where
passing in `#f` means something distinct from an absent argument. In my
opinion, it's a design mistake in the procedure if it needs to make that
distinction. Good procedures are easy to use correctly without detailed
study. If we know that most keyword args use #f as a default, but make
one procedure that uses #f for something else, that's just the kind of
special case that people are prone to forget in a hurry. I would prefer
a language that encourages people to design simple interfaces to their
procedures. What I learned from Common Lisp is that when the language
has a sophisticated lambda-list syntax, people get excited about it
(myself included) and use it to design over-complicated interfaces to
simple tools.

The good thing about the above `let` technique is that the `let` is
inside the procedure. Whatever you do in R7RS-large, please do _not_
make the CL mistake of allowing the default value to be specified as an
expression embedded in the lambda list itself. That is just awful :) You
can't tell what scope it's evaluated in (well, I could always go back
and read the fine print in CLHS for the umpteenth time, then forget it
again in a month).

And if a wrapper needs to pass the default value, it may not even be
able to compute that value because the default-value computation relies
on things that are in the lexical scope of the keyword lambda but not in
scope of the wrapper. Ugh.

None of the above does anything to advance good software engineering in
any way. It's a mental playground created for its own sake, because too
much intelligence was applied to the problem and it sounded like in
principle somebody might need it one day.

If, against my repeated and experience-backed warnings, R7RS-large wants
to allow non-#f defaults, the (default? <argname>) primitive you
proposed is far better than the CL solution of supplied-p parameters in
the lambda list. Common Lisp uses the term "supplied" to talk about
parameters that are given by the caller. So it could be named (supplied?
<argname>) for example.

I don't care about what name such an extension will finally have.

But I care to be able to distinguish between a non-supplied argument and #f as these are, logically, two different things.

Maybe I would like to handle a tri-state keyword argument: true/false/use whatever default value.  The default should be the default, not #f.


(parameterize ((default-case-sensitivity #t))
  (foo case-sensitivity: #t)
  (foo case-sensitivity: #f))

Languages become simpler if they do not lump together things that are logically different.

Scheme is a better language because '() and #f are different objects.

Whatever you do, please do not have anything except argument names in
the lambda-list grammar. Those lists get unwieldy very fast if you put
anything except argument names in there. Been there, have the memories.

I can agree on this.