Module niltoken
Module to provide Nil token.
Purpose
The nil value is somewhat special in Lua, and can be difficult to use
in some contexts. This module offers a unified way to circumvent these
difficulties.
The problem
In Lua, nil means "nothing". As such, in a table, there is no way to
tell apart a key associated with the value nil from a key which doesn't
exist at all in this table. For instance, { foo=123, bar=nil } is exactly
the same as { foo=123 }.
However, in some contexts, Lua tables are used to represent data structures
which might contain a NULL/nil value. For instance, if the server wants
to indicate that it erased the variable foo, it cannot simply send the
record { foo=nil }: it would be undistinguishable from the empty record
{ }. Similarly, Hessian has a Null value which almost naturally maps to
Lua's nil; but Hessian's Null can be used as a record value, and even as
a record key, whereas Lua's nil can't.
The solution
The way to address those issues of representing a null value when nil can't
be used is to have a token, an arbitrary object which by convention means null.
Whenever the need for such a token appears, we use the same niltoken object
as this token.
It is preferable for niltoken not to be a naturally easy to serialize type,
such as a table. This mainly leaves userdata and functions as good candidates.
For reasons exposed below, it has been decided to represent niltoken as
a function.
Converting between niltoken and nil
There are three common operations to perform on niltoken and tables likely
to contain references to niltoken:
- Test for equality with
niltoken, as inif foo==niltoken then ... end; - Convert
niltokenreferences into actualnil; - Convert
nilvalues intoniltokenreferences.
Equality tests are performed by the usual == Lua operator. Conversions
are performed by niltoken itself, which is a function:
- It converts
niltokenreferences intonil:assert(niltoken(niltoken)==nil); - It converts
nilvalues intoniltokenreferences:assert(niltoken(nil)==niltoken). - It leaves everything else alone:
if a~=nil and a~=niltokenthen assert(niltoken(a)==a) end`.
Packaging
the niltoken function is directly returned as the niltoken module, i.e.
the idiomatic way to use it is to put a local niltoken = require 'niltoken'
statement at the top of modules which might need it.