While working with Gauche, sometimes you encounter
a value printed as #<undef>
, an undefined value.
gosh> (if #f #t) #<undef>
It is a value used as a filler where the actual value doesn’t matter, or there’s no other suitable value, or the binding hasn’t been calculated.
Do not confuse undefined values with unbound variables;
A variable can be bound to #<undef>
, for it is just
an ordinary first-class value. On the other hand, an
unbound variable means there’s no value associated with the variable.
However, #<undef>
may be used in certain
occasions to indicate that a value is not provided for
the variable. For example,
the toplevel variable can be bound to #<undef>
if it is
defined by (define variable)
form (see Definitions).
An optional procedure parameter
without default value is bound to #<undef>
if an
actual argument is not given (see Making procedures).
Note that it cannot be distinguished from the case
a value is actually provided, and the value just happens
to be #<undef>
. If you get an #<undef>
,
you can say at most is that the value doesn’t matter.
You shouldn’t let it carry too much meanings.
The #<undef>
value is counted as true value in generalized
boolean context,
since it is not #f
. However, branching based on #<undef>
is dangerous—a procedure that is defined to return unspecified value
may merely returning #<undef>
as a provisional value; it will
change the return value in future. Since the return value isn’t specified,
no one should be using it. The code that tests such result value as
a generalized boolean may break if the procedure changes the return value.
In fact, we’ve found that there are quite a few code that accidentally tests
#<undef>
return value in conditionals. They can be seeds
for future bugs, so we warn when #<undef>
value
is used in the test of branches. You can suppress the warning with
setting the environment variable GAUCHE_ALLOW_UNDEFINED_TEST
.
One typical case of such accidental use of #<undef>
branching
is in and-let*
; the following code assumes display
always return
#<undef>
, which is counted as a true value, and expects the control
to proceeed to the next clause. It’ll break if display
ever changes
so that it may return #f
in some cases.
(and-let* ([var (foo x y z)] [ (display var) ] ;; branch on #<undef> [baz (bar var)]) ...)
Being said that, there are a couple of procedures to deal with undefined values.
Returns #t
iff obj is an undefined value.
Returns an undefined value.