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.