www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - How to check for null references

reply =?ISO-8859-1?Q?Hans-Eric_Gr=f6nlund?= <hasse42g gmail.com> writes:
Hi all!

I'm trying to learn D, mostly by trial and error, and I keep tripping over the
smallest rocks. This time the pebble is:
How can I gracefully check if an object reference is null? I get an access
violation if I try this and the reference (o) is null:

if (o == null) {...}

Is this a bug in DMD (I use the stable 1.x version) or did I miss something
obvious?

Best regards

Hans-Eric Grönlund
Software Developer, Project Manager, Freelance Journalist
http://www.hans-eric.com/
Aug 27 2007
next sibling parent reply Carlos Santander <csantander619 gmail.com> writes:
Hans-Eric Grönlund escribió:
 Hi all!
 
 I'm trying to learn D, mostly by trial and error, and I keep tripping over
 the smallest rocks. This time the pebble is: How can I gracefully check if an
 object reference is null? I get an access violation if I try this and the
 reference (o) is null:
 
 if (o == null) {...}
 
 Is this a bug in DMD (I use the stable 1.x version) or did I miss something
 obvious?

Use: if (o is null) {...}
 
 Best regards
 
 Hans-Eric Grönlund Software Developer, Project Manager, Freelance Journalist 
 http://www.hans-eric.com/

Since you're learning D, questions like this one are better suited for the D.learn newsgroup. -- Carlos Santander Bernal
Aug 27 2007
parent =?ISO-8859-1?Q?Hans-Eric_Gr=f6nlund?= <hasse42g gmail.com> writes:
Thank you! I'll direct the basic questions to the learn-newsgroup from now on.

/Hans-Eric

Carlos Santander Wrote:

 Hans-Eric Grönlund escribió:
 Hi all!
 
 I'm trying to learn D, mostly by trial and error, and I keep tripping over
 the smallest rocks. This time the pebble is: How can I gracefully check if an
 object reference is null? I get an access violation if I try this and the
 reference (o) is null:
 
 if (o == null) {...}
 
 Is this a bug in DMD (I use the stable 1.x version) or did I miss something
 obvious?

Use: if (o is null) {...}
 
 Best regards
 
 Hans-Eric Grönlund Software Developer, Project Manager, Freelance Journalist 
 http://www.hans-eric.com/

Since you're learning D, questions like this one are better suited for the D.learn newsgroup. -- Carlos Santander Bernal

Aug 27 2007
prev sibling next sibling parent Jascha Wetzel <"[firstname]" mainia.de> writes:
Hans-Eric Grönlund wrote:
 Hi all!
 
 I'm trying to learn D, mostly by trial and error, and I keep tripping over the
smallest rocks. This time the pebble is:
 How can I gracefully check if an object reference is null? I get an access
violation if I try this and the reference (o) is null:
 
 if (o == null) {...}
 
 Is this a bug in DMD (I use the stable 1.x version) or did I miss something
obvious?
 
 Best regards
 
 Hans-Eric Grönlund
 Software Developer, Project Manager, Freelance Journalist
 http://www.hans-eric.com/

the "==" operator can be overloaded and D implicitly dereferences pointers to structs/classes, therefore the identity operator "is" and "!is" has to be used.
Aug 27 2007
prev sibling parent reply Tim Healey <leikeze gmail.com> writes:
Use 'is' to test for null:

if ( o is null ) { ... }

 From http://www.digitalmars.com/d/expression.html#IdentityExpression : 
For class objects, identity is defined as the object references are for 
the same object. Null class objects can be compared with is.

The run-time error you got is because the program was essentially 
executing this:

if ( o.opEquals( null ) ) { ... }

This is intended behavior, though I'm not finding the right spec page to 
link you to at the moment.
Aug 27 2007
parent reply =?ISO-8859-1?Q?Hans-Eric_Gr=f6nlund?= <hasse42g gmail.com> writes:
Thank you Tim (and the others that pointed this out)! I had a feeling there'd
be a simple answer.

Tim Healey Wrote:

 Use 'is' to test for null:
 
 if ( o is null ) { ... }
 
  From http://www.digitalmars.com/d/expression.html#IdentityExpression : 
 For class objects, identity is defined as the object references are for 
 the same object. Null class objects can be compared with is.
 
 The run-time error you got is because the program was essentially 
 executing this:
 
 if ( o.opEquals( null ) ) { ... }
 
 This is intended behavior, though I'm not finding the right spec page to 
 link you to at the moment.

Aug 27 2007
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
This one seems to trip up a lot of new users. Is there some way (short of
making it huge, red, and flashing) to make this somehow more obvious o the D
webpage. I'm sure it trips up quite a few people who already know the rule, too
(I don't do too much D work, and I've already been bitten once or twice).

I think the best way might be to issue a compiler error if an object doesn't
have an opEquals() overload instead of providing a default implementation in
object (like for all the other operator overloads). That would break a lot of
existing code, though, but the compiler would help fix it rather than having it
break silently.

Hans-Eric Grönlund Wrote:

 Thank you Tim (and the others that pointed this out)! I had a feeling there'd
be a simple answer.
 
 Tim Healey Wrote:
 
 Use 'is' to test for null:
 
 if ( o is null ) { ... }
 
  From http://www.digitalmars.com/d/expression.html#IdentityExpression : 
 For class objects, identity is defined as the object references are for 
 the same object. Null class objects can be compared with is.
 
 The run-time error you got is because the program was essentially 
 executing this:
 
 if ( o.opEquals( null ) ) { ... }
 
 This is intended behavior, though I'm not finding the right spec page to 
 link you to at the moment.


Aug 27 2007
parent reply Nathan Reed <nathaniel.reed gmail.com> writes:
Robert Fraser wrote:
 This one seems to trip up a lot of new users. Is there some way (short of
making it huge, red, and flashing) to make this somehow more obvious o the D
webpage. I'm sure it trips up quite a few people who already know the rule, too
(I don't do too much D work, and I've already been bitten once or twice).
 
 I think the best way might be to issue a compiler error if an object doesn't
have an opEquals() overload instead of providing a default implementation in
object (like for all the other operator overloads). That would break a lot of
existing code, though, but the compiler would help fix it rather than having it
break silently.
 

How about just issuing a warning if 'null' is on either side of an == sign? Thanks, Nathan Reed
Aug 27 2007
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Nathan Reed Wrote:

 Robert Fraser wrote:
 This one seems to trip up a lot of new users. Is there some way (short of
making it huge, red, and flashing) to make this somehow more obvious o the D
webpage. I'm sure it trips up quite a few people who already know the rule, too
(I don't do too much D work, and I've already been bitten once or twice).
 
 I think the best way might be to issue a compiler error if an object doesn't
have an opEquals() overload instead of providing a default implementation in
object (like for all the other operator overloads). That would break a lot of
existing code, though, but the compiler would help fix it rather than having it
break silently.
 

How about just issuing a warning if 'null' is on either side of an == sign? Thanks, Nathan Reed

I guess my problem is this (taken from object.d): int opEquals(Object o) { return cast(int)(this is o); } All object.opEquals() is doing is invoking "is", so it's kind of tricking people who don't know/remember that == doesn't test for identity and theoretically (it'd probably be inlined, but still) slowing down code. What's the point? Seems like it'd be better all around to get rid of it entirely.
Aug 27 2007
next sibling parent reply Sean Kelly <sean f4.ca> writes:
Robert Fraser wrote:
 Nathan Reed Wrote:
 
 Robert Fraser wrote:
 This one seems to trip up a lot of new users. Is there some way (short of
making it huge, red, and flashing) to make this somehow more obvious o the D
webpage. I'm sure it trips up quite a few people who already know the rule, too
(I don't do too much D work, and I've already been bitten once or twice).

 I think the best way might be to issue a compiler error if an object doesn't
have an opEquals() overload instead of providing a default implementation in
object (like for all the other operator overloads). That would break a lot of
existing code, though, but the compiler would help fix it rather than having it
break silently.

Thanks, Nathan Reed

I guess my problem is this (taken from object.d): int opEquals(Object o) { return cast(int)(this is o); } All object.opEquals() is doing is invoking "is", so it's kind of tricking people who don't know/remember that == doesn't test for identity and theoretically (it'd probably be inlined, but still) slowing down code. What's the point? Seems like it'd be better all around to get rid of it entirely.

opEquals needs to be in Object because it is used by the AA code. However, it could be changed to simply throw an exception, thus requiring users to override it. Sean
Aug 27 2007
next sibling parent Daniel Keep <daniel.keep.lists gmail.com> writes:
Sean Kelly wrote:
 [snip]
 
 opEquals needs to be in Object because it is used by the AA code.
 However, it could be changed to simply throw an exception, thus
 requiring users to override it.
 
 Sean

Just a note: I just re-read what you said and realised you meant it should throw an exception in all cases. I thought you meant if you were trying to compare to null (duh). I'm not sure if I'm for or against that idea, but it would certainly fix the problem. Especially if the error was "Use the is operator, and read the documentation!" :P (Although, that doesn't help us if they haven't worked out they need to use 'new', but you can't have everything :P) -- Daniel Just because I put a lot[1] of effort into it, here's what I was *going* to write: [1] When I say "a lot" I mean "had to write, compile, debug and disassemble a test program immediately after waking up." I deserve a *medal* for that! module nullobj; class Foo { int opEquals(Object other) { throw new Exception("AARGH, GOODBAI KRUUL WURLD!"); } } void main() { Foo foo; bool foundit = cast(bool)(foo == null); } -----
 dmd nullobj && nullobj

See, it already throws an exception! :P Let's see what happens when we disassemble the code in main: nullobj.d:11 void main() 0040204c: c8080000 enter 0x8, 0x0 nullobj.d:13 Foo foo; 00402050: 31c0 xor eax, eax 00402052: 8945f8 mov [ebp-0x8], eax nullobj.d:14 bool foundit = cast(bool)(foo == null); 00402055: 50 push eax 00402056: 8b08 mov ecx, [eax] 00402058: ff5114 call dword near [ecx+0x14] 0040205b: f7d8 neg eax 0040205d: 19c0 sbb eax, eax 0040205f: f7d8 neg eax 00402061: 8845fc mov [ebp-0x4], al 00402064: 31c0 xor eax, eax nullobj.obj 00402066: c9 leave 00402067: c3 ret Ok, look at the call and the lines above it. That's the line where we call opEquals. But notice how we're doing it? We're calling it by using one of the vtable functions, stored as an offset from the start of the object. But the object's null, so when we try to work out where the opEquals function is... BOOM. So yes, we *can* already have opEquals throw an exception if the object's null. It just has to be a segfault, since if the object's null, we can't find opEquals. As an aside, I love ddbg ^_^
Aug 27 2007
prev sibling parent "Stewart Gordon" <smjg_1998 yahoo.com> writes:
"Sean Kelly" <sean f4.ca> wrote in message
news:favmpt$fkr$1 digitalmars.com...
 Robert Fraser wrote:

 All object.opEquals() is doing is invoking "is", so it's kind of tricking 
 people who don't know/remember that == doesn't test for identity and 
 theoretically (it'd probably be inlined, but still) slowing down code. 
 What's the point?  Seems like it'd be better all around to get rid of it 
 entirely.


To serve as a default equality test for classes that don't implement their own.
 opEquals needs to be in Object because it is used by the AA code. 
 However, it could be changed to simply throw an exception, thus requiring 
 users to override it.

What would the point of this be? I don't see there being any such thing as there being a class with no concept of equality, not even that of being one and the same object. Besides, as at least one person has already said, this does nothing for the original subject: the null reference checking problem. Stewart.
Aug 28 2007
prev sibling parent reply Nathan Reed <nathaniel.reed gmail.com> writes:
Robert Fraser wrote:
 I guess my problem is this (taken from object.d):
 
 int opEquals(Object o)
 {
     return cast(int)(this is o);
 }
 
 All object.opEquals() is doing is invoking "is", so it's kind of tricking
people who don't know/remember that == doesn't test for identity and
theoretically (it'd probably be inlined, but still) slowing down code. What's
the point? Seems like it'd be better all around to get rid of it entirely.

It probably should be removed, or replaced by a throw, but this doesn't change the fact that if you use == to test for null references, you get a runtime error and there's no indication of the problem at compile time. A warning would be helpful (or even an error, since AFAIK there's no situation where writing 'o == null' is the right thing to do). (OT) by the way, is there a reason opEquals returns int? I'm sure people have pointed this out before, but bool would seem to be more natural. Thanks, Nathan Reed
Aug 27 2007
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Nathan Reed wrote:
 Robert Fraser wrote:
 I guess my problem is this (taken from object.d):

 int opEquals(Object o)
 {
     return cast(int)(this is o);
 }

 All object.opEquals() is doing is invoking "is", so it's kind of 
 tricking people who don't know/remember that == doesn't test for 
 identity and theoretically (it'd probably be inlined, but still) 
 slowing down code. What's the point? Seems like it'd be better all 
 around to get rid of it entirely.

It probably should be removed, or replaced by a throw, but this doesn't change the fact that if you use == to test for null references, you get a runtime error and there's no indication of the problem at compile time. A warning would be helpful (or even an error, since AFAIK there's no situation where writing 'o == null' is the right thing to do).

 (OT) by the way, is there a reason opEquals returns int?  I'm sure 
 people have pointed this out before, but bool would seem to be more 
 natural.
 

About the opEquals return value: http://www.prowiki.org/wiki4d/wiki.cgi?DocComments/OperatorOverloading --bb
Aug 27 2007
prev sibling parent Sean Kelly <sean f4.ca> writes:
Nathan Reed wrote:
 
 (OT) by the way, is there a reason opEquals returns int?  I'm sure 
 people have pointed this out before, but bool would seem to be more 
 natural.

It's a historic issue regarding code generation and should be changed. Sean
Aug 27 2007