-
chevron_right
The case against IF-LET*
Michał "phoe" Herda · Monday, 15 April, 2019 - 11:49 edit · 1 minute
Someone asked a question on #lisp
on Freenode: since WHEN-LET
has an analogous
WHEN-LET*
, why IF-LET
has no analogous IF-LET*
?
Here is my attempt at answering it.
Suppose we have a following code block:
(if-let ((x 42)
(y nil)
(z :foo))
(list :true x y z)
(list :false x y z))
All of X
, Y
, and Z
are bound to the respective values: 42
, NIL
, and :FOO
. At least one of the values
is false. Therefore, it should be obvious that the result of evaluating this code would be the list
(:FALSE 42 NIL :FOO)
.
Now, let us slightly modify this code:
(if-let* ((x 42)
(y nil)
(z :foo))
(list :true x y z)
(list :false x y z))
We no longer use IF-LET
but instead we use the hypothetical sequential version, IF-LET*
. We evaluate X
and Y
.
By definition, we are supposed to not evaluate the following variables at this moment, since Y
evaluated to false,
and we instead execute the false branch.
The big question is: what is the value of Z
in the false branch?
It is certainly not :FOO
because we have not managed to evaluate that binding yet. In fact, that lexical variable
should be unbound since there is no logical value for it, but there is no such thing as an unbound lexical variable in Lisp.
In particular, this might mean that we encounter any number of logically unbound variables in the false branch.
We could work around it by setting the not-yet-bound lexical variables to some predefined value (which would
greatly complicate the code and introduce a lot of mess) or we would make the false branch unable to use any of the lexical
bindings, which makes the sequential IF-LET*
greatly inconsistent with the parallel IF-LET
.
In other words: having IF-LET*
would be inconsistent. None of the variables are available in the lexical scope of the false branch, and that should be part of IF-LET*
's contract.