The Nil Object In Strongly Typed Languages

From TheNilObject...

The type of the nil object in strongly typed languages is problematic: either you have to extend every type to include its own special nil value, or you have to start working with polymorphic types.


Discussion moved From NullObjectDiscussion...refactoring to follow...

Please help me construct this to make the discussion most informative for all...

Suppose the following types are defined:

 Foobar
 FoobarOrNil?
 Zeetix
 ZeetixOrNil?
 Nil

Suppose the following types are contemplated:
 NilFoobar?
 NilZeetix?

This discussion assumes that NilObject? is a singleton with one distinguished instance, TheNilObject. This discussion also assumes that FoobarNilObject?, ZeetixNilObject? are also singletons with one distinguished instance of each, TheFoobarNilObject? and TheZeetixNilObject?.

The first big question, I believe, is the following:

Is TheNilObjectInStronglyTypedLanguages required at all?

followed by its companion:

If some Nil object is required, are NilFoobar? and NilZeetix? also required (for each type whose value range includes "no value")?


Suppose they are -- then let me ask some simple questions:

  1. How shall either TheNilFoobar? or TheNilZeetix? respond to the #isNil and #notNil methods?

  2. How many kinds of NilWhatever? should there be (for example, one per MumbleOrNil?)?

  3. Shall TheNilFoobar? be included in an enumeration/extension of FoobarOrNil?? Foobar?

For better or for worse, Nil represents a singularity in a strongly typed system. Perhaps someone more informed than I can present a better answer.

(A: See below.)

The rub here, from a type-theoretical viewpoint, is that a system that alleges to be strongly typed has to determine whether Nil is or is not a member of an arbitrary type other than its own type.

I tried to edit this so that it makes sense in this context -- please help where I've failed... It has to be its own type; otherwise you are introducing a nonsensical domain value into every type. Should there be a Nil value in the domain of integers? The problem with TheNilObject is the programming language which says that every reference (or pointer) variable has a special null value that doesn't refer to any object. By eliminating this idiocy, you not only simplify the TheNilObjectInStronglyTypedLanguages down to nothing, but you also help a safe compiler eliminate generating null-pointer checks. Under this type system, if an object is declared to be of some non-null type, then you know that it can't be a null reference. In a type system in which every object of some declared type can still be a null reference, the declaration doesn't help the compiler.

From a practical perspective, I've had more success (in Smalltalk) by extending the protocol of UndefinedObject to include the behavior suggested for NilFoobar?. This gets most of the way there, but only because Smalltalk is untyped. Things get much more muddled with methods that count instances, check cardinality of impending assignments, and compare instances.

For example, designs that assume that Foobar and Zeetix are disjoint (for example,

  Zeetix>>isNotFoobar
^true

Foobar>>isNotFoobar ^false

have difficulty supporting NilZeetix? and NilFoobar? while maintaining reasonable semantics about Nil itself. These, by the way, are *semantic* problems, not syntactic.

I've struggled with this a long time, because I find the pattern very appealing. So ... I'd love to see any answers! --TomStambaugh


<Candidate for deletion> Let me give some simple answers:

  1. How shall one of these NilObject?s respond to the #isNil and #notNil methods? -- obviously a NullObject is not nil. The two concepts are very different.

  2. How many kinds of UndefinedObject should there be? -- what's this got to do with anything? A NullObject is not undefined.

  3. Shall NilFoobar? be included in an enumeration/extension of Foobar? -- depends on what Foobar is. To use an example from below, /dev/null is a valid filename name, yet is a NullObject for files/streams.

RE: "Nil represents a singularity in a strongly typed system."

-- yes, but a NullObject has nothing to do with nil. In principle, a reference to an object that could hold a NullObject for its type might be nil. In this case, the value of the reference is nil, not its NullObject

-- AnonymousDonor


RE: "How many kinds of UndefinedObject should there be?"

A: As many as you want. Typically, one would have a different NullObject class for each type of client that needs it: NullShape?, NullLayoutManager?, NullEmailProtocol?, etc. The NullObject classes do not necessarily have any relationship to each other -- or to nil or the UndefinedObject class. -- JeffGrigg


</Candidate for deletion>

The basic problem is Liskov Substitutability - Nil cannot always be used in every context the base class can be. The NilObject? tries to patch it by defining a null object which can be so used.

Many statically type-checked languages (including C, C++, Java and Eiffel) treat NULL as a subtype of every type even though it isn't. At least one language, Cecil, has a system in which NULL is not a subtype, so the static type checker will catch any attempt to misuse a variable which could be NULL. This means you have to be more explicit about what is going on, but I think that's probably a good thing (especially as Cecil's type-checker is optional). -- DaveHarris

There is no problem with LSP. NullObject<Foobar,maybe Purpose> and Foobar are subtypes of FoobarOrNullObject?<maybe Purpose>. --NikitaBelenki


I think the problem here is that NilIsNotProfound?. It does not have any one consistent meaning; it is just a convenience. In many domain types there is one "special" value that is distinct from any "normal" value, and it is convenient to use Nil for that value. In many other domain types there is no such special value, and any use of Nil as a value of one of those types is an error -- it would be better if the coded type in use could not be assigned Nil. In other domain types there are more than one special value (like FP maths with +Inf, -Inf, NaN etc.) In those cases Nil is useless, and there is no alternative but to complicate the coded type to include the needed special values.

The existence of Nil is not some profound truth about the universe or about OO modelling, it is just a convenience that covers the many cases where you want one special value, causes not too much problem for the many cases where you don't need one. You could perfectly well have a strongly-typed OO language with no build-in concept of Nil, but some jobs would become a bit more awkward.

Given all this, arguing about what the "one true meaning" of Nil is and how is should be correctly implemented is a bit pointless.

I think you've asked perhaps the "biggest" question of all...which I've moved to the top of the page. So do I take your comments to mean that you recommend against any Nil object (the Java/C++ approach)?


CategoryNull


EditText of this page (last edited August 28, 2007) or FindPage with title or text search