www.digitalmars.com         C & C++   DMDScript  

D - Null object semantics

reply "Les Baker" <lesbaker innovaREMOVETHIS.net> writes:
I've been lurking for a while, and I wanted to suggest a feature that seems
to partly be in the language already. That is automatically generated null
objects for each class. Why I say this is that floating-point numbers have
this already.

Looking on the "Expression" and "Properties" pages of the D manual, floating
point numbers have null semantics, because their "init" property is the
special NaN value. The floating point numbers also have special comparison
operators to specificially handle cases in which an operand is NaN. Why
can't UDT's have that capability as well (note that although I'm mainly
talking about classes, structs might apply to this as well)?

What I'm thinking of is a static object field that is attached to each
class. This object would get its static constructor run and member fields
initialized, and any other fields initialized to their .init value
(including contained objects). Then, when an object gets initialized without
any new expression:

Class obj;

then it gets set to the .init static object.

Methods would need some syntax to indicate what their "do nothing" return
value is.

class Person
{
    char[] name;
    int id;

    int getID() = 0
    {
        return id;
    }

    char[] getName() = "<null name>"
    {
        return name;
    }
}

(Well, I'll admit that was a bit contrived... couldn't think of anything
better at the moment)

The above syntax would be inadequate if something more needed to be done
when a method was called on a null object... like make a log entry, bail out
of the program, whatever.

I want to emphasize I'm not making a hard and fast "proposal". I'm hoping
discussion will generate from this, and an OO guru will shape something up
and present something very compelling that Walter will like :-)

One other nice benefit is that null object semantics would mesh very nicely
with the foreach already in D. For example, if I were programming an
Internet server with a fixed pool of connections, and the server was
shutting down, then something like this could be coded

Connection conn;

foreach( conn; connectionPool )
    conn.shutdown();

and the right thing would happen without worrying about if all the
connections in the pool were actually live.

Any thoughts?

Thanks -- Les Baker

PS. This post is also a "yes vote" for the opIn operator overload discussed
a while back. :-)
Feb 11 2004
parent Ilya Minkov <minkov cs.tum.edu> writes:
Les Baker wrote:
 I've been lurking for a while, and I wanted to suggest a feature that seems
 to partly be in the language already. That is automatically generated null
 objects for each class. Why I say this is that floating-point numbers have
 this already.

Do you come from Java background? It seems to me you have some sort of weird understanding of the world of zeroes and ones. :>
 Looking on the "Expression" and "Properties" pages of the D manual, floating
 point numbers have null semantics, because their "init" property is the
 special NaN value. The floating point numbers also have special comparison
 operators to specificially handle cases in which an operand is NaN. Why
 can't UDT's have that capability as well (note that although I'm mainly
 talking about classes, structs might apply to this as well)?

If you declare a class instance in your code, it gets automatically assigned "null", which is a pointer constant analogeous to C NULL. Which means invalid pointer, or in the case of an object a non-exisiting object.
 What I'm thinking of is a static object field that is attached to each
 class. This object would get its static constructor run and member fields
 initialized, and any other fields initialized to their .init value
 (including contained objects). Then, when an object gets initialized without
 any new expression:

Object.init == null
 Class obj;
 
 then it gets set to the .init static object.
 
 Methods would need some syntax to indicate what their "do nothing" return
 value is.

The problem is, methods can only be called on exisiting objects. Making methods work "almost normally", that is, returning some rubbish values, on objects that don't exist would severely endanger language safety, besides killing performance. Especially, it would make it *very* hard to spot out that some object has not been created at some moment and why. Besides, it is not technically feasible, because method called depends on the object actually created, That is, it could be the object of the same actual as formal type, or an actual type can be subtype of a formal type. For that reason, objects contain a hidden pointer into an array which contains adress of actual implementation of each function. Now, if there is no object, you cannot decide what to do...
 I want to emphasize I'm not making a hard and fast "proposal". I'm hoping
 discussion will generate from this, and an OO guru will shape something up
 and present something very compelling that Walter will like :-)

I hope your message gets ignored else you might get flamed. ;)
 One other nice benefit is that null object semantics would mesh very nicely
 with the foreach already in D. For example, if I were programming an
 Internet server with a fixed pool of connections, and the server was
 shutting down, then something like this could be coded

This could be the functionality of a pool not to iterate through non-exising objects - which is easy to determine by checking them for null. ;) BTW, to check manually there are 2 ways: - Object implicitly converts into boolean - true if it exists, false if it's a null so: if (myObject) //my object is alive { /* do something */ } if (!myObject) //whoops! forgot to create an object! { /* create an object now */ } - A reference comparison is done with === (or is) operator (phew!) if (myObject !== null) //my object is alive { /* do something */ } if (myObject is null) //whoops! forgot to create an object! { /* create an object now */ }
 and the right thing would happen without worrying about if all the
 connections in the pool were actually live.

All means are just already there.
 PS. This post is also a "yes vote" for the opIn operator overload discussed
 a while back. :-)

? I am apparently yet to find it. -eye
Feb 12 2004