3 ms·
Do we really need null?
- _delirium 16y agoAnother possible solution is to require initialization of reference types upon declaration, instead of silently supplying a new default object if no initialization is given. A bit more verbose, but might be clearer (esp. in Java-land, where stuff happening behind the scenes without explicit code is frowned on). Ocaml basically does that, though it feels sort of second-nature rather than a restriction, because syntactically, the only way to get a reference is to take a reference of something. Eiffel "attached types" are similar (guaranteed to always be "attached" to a non-Void value), but have a somewhat more complex scheme of possibilities: http://docs.eiffel.com/sites/docs.eiffel.com/files/void-safe-eiffel.pdf http://docs.eiffel.com/sites/docs.eiffel.com/files/void-safe... A big potential problem, I think, would be whether people use null-setting patterns often enough that they would work around the proposed change, by using these default-constructed objects as glorified null values, maybe by having them set an "I'm a dummy object" flag internally or something.
- cperciva 16y agoYes, we really do need NULL. It's very useful in a number of data structures; for example: struct node { char * key; char * value; struct node * left; // NULL if we have no left child struct node * right; // NULL if we have no right child } Sure, you could add a separate "int flags" field to record which children a node has, but that would just make the code slower and cause it to use more RAM.
- vmathew 16y agoA systems programming language that expose pointers will not be able to shed NULL. But a higher-level language can and a "pure" OOP language should - because null make objects unable to respond to messages. Something that claims to belong to the type system and cannot respond to messages just don't fit in there.
- cperciva 16y agoOk, I'll bite: In your idea of a perfect object-oriented language, how do you encode "we might or might not have a left child"?
- vmathew 16y agoThis is one possible way of doing it: class Node { static const Node EMPTY_NODE = Node(); String key; String value; Node left = EMPTY_NODE; Node right = EMPTY_NODE; Node(String key, String value) { this.key = key; this.value = value; } static void traverseInorder(Node n, Visitor v) { if (n.left != EMPTY_NODE) { traverseInorder(left, v); } v.visit (n); if (n.right != EMPTY_NODE) { traverseInorder(right, v); } } }
- cperciva 16y agoOk, and how exactly is that different from using NULL, aside from being more complicated?
- vmathew 16y agoclass Node { // May not be a real situation for a Node class, // but makes a point. Node getLeft() { return left; } } // No more checks against NULL. In fact code becomes simpler for // the user of the library. node.getLeft().getLeft().getValue(); I don't think the class definition is much too complicated, except for the declaration of the EMPTY field. What we need is a non-mutable, class-wide, default object, not null. We don't need to explicitly declare this object, if the language does that for us and make it accessible through a keyword - say 'default': if (n.left != default) { traverse(n.left); }
- cheald 16y agoRuby uses a nil type, but due to its flexibility, nil can also respond to messages! Its presence is greatly appreciated, and it's not a NULL in the "This is a pointer to 0x0" sense, but in terms of how you use it, it's functionally equivalent. By means of example: irb(main):003:0> nil.class => NilClass irb(main):004:0> nil.nil? => true irb(main):005:0> nil.methods => ["inspect", "method", "tap", "&", "clone", "public_methods", "__send__", ...] irb(main):006:0> nil.is_a? String => false
- DCoder 16y agoConditional initialization? Suppose I have several objects of the same type and need to do manipulations on one of them, which one depends on something: Foo * pFoo = NULL; if(x) { // stuff pFoo = Foo::p1; } else { // stuff pFoo = Foo::p2; } if(pFoo) { pFoo->bar(); } I can't declare pFoo inside if(x) due to scoping, so I have to declare it before initializing it meaningfully. It has to be either a pointer to the object (references don't work without initialization) or an object copy, which would not modify the original object...
- vmathew 16y agoIn the first place, a language that exposes pointers may not be able to do away with null. But as for languages like Java, the problem can be solved with the help of an implicit, non-mutable default object: Foo foo; // initialized to default if (x) { // stuff foo = Foo.p1; } else { // stuff foo = Foo.p2; } // No need to check if this is a valid reference, it always will be. foo.bar();