Gaucheで作業していると、しばしば未定義値 #<undef>
に出会うことがあるでしょう。
gosh> (if #f #t) #<undef>
この値は、値そのものに意味が無いこと、 ほかにふさわしい値が無いこと、あるいは束縛する値がまだ計算されていないことを示します。
未定義値と未束縛の変数を混同しないようにしてください。
#<undef>
は通常の第一級の値であり、変数に束縛しておくこともできます。
未束縛の変数は文字通り、変数が束縛されていない、すなわち値を持たないことを意味します。
しかし、場合によっては、変数に特定の値が提供されていないことを
示すのに#<undef>
が使われることもあります。
例えば、トップレベル変数は、(define variable)
の形式で定義された場合に
#<undef>
に束縛されます(定義参照)。
また、既定値をもたない省略可能引数に実引数が提供されなかった
場合、引数の値は#<undef>
となります (手続きを作る参照)。
これは実際に#<undef>
が初期値として、あるいは引数として渡された場合と区別がつかない
ことに注意してください。#<undef>
を受け取ってわかることは、
せいぜいその値にたいした意味がないということくらいです。
#<undef>
に大きな意味を持たせすぎないようにしましょう。
#<undef>
は一般化された真偽値としては真の値とみなされます
(偽になるのは#f
のみですから)。
しかし、#<undef>
の値を見て分岐するコードは危険です。
というのも、戻り値が規定されていない手続きが暫定的に#<undef>
を返している
場合が良くあるからです。でも、それは将来変更されるかもしれません。
戻り値が規定されていない以上、戻り値に依存するコードは無いはずだからです。
もしうっかり、その戻り値に基づいて分岐しているコードがあると、変更があったときに
壊れてしまいます。
実のところ、#<undef>
に依存して分岐しているコードが結構多いことがわかりました。
これは将来のバグの芽となるので、#<undef>
が分岐テストに現れた時に
警告する機能がつけてあります。環境変数GAUCHE_CHECK_UNDEFINED_TEST
をセットすることでその機能をオンにできます。
将来、テストの際にこの機能をオンにするかもしれません。
#<undef>
をうっかり分岐テストに使ってしまう良くあるパターンは、
and-let*
です。次のコードでは、print
がテスト節に現れていますが、
このコードはprint
が常に#<undef>
を返しそれが真の値であることから
次のテスト節に進むことを期待しています。けれども、print
が場合によっては#f
を
返すように変更されたら、このコードは壊れてしまいます。
(and-let* ([var (foo x y z)] [ (print var) ] ;; branch on #<undef> [baz (bar var)]) ...)
以上の注意を念頭においた上で、未定義値を扱うには 次の手続きが利用できます。
objが未定義値である場合に限り#t
を返します。
未定義値を返します。