Okay, no cheating now. That is, no running the code until you’ve guessed.
What is the output of this code?
program Project90; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; var S: TObject; begin try S := nil; if S is TObject then begin Writeln('Yup'); end else begin Writeln('Nope'); end; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Readln; end.
How sure are you?
Now run it and find out. Were you right?
Well, I wasn’t right. I tought that an exception would be raised. Nil aka null always introduced the “third possible state” ambiguity. I’m not actually sure what should actually happen. Hated nil since the beggining, it brings in so much FUD
I guessed right: the is operator always returns False with nil.
Wanna really break your brain, though? Add a second variable, T: TObject. Add in a line after the assignment:
T := S as TObject;
What is the resulting behavior?
I haven’t had time to try this yet – what is the behaviour? I’m going to guess something odd 🙂
Pointer isn’t it? From pascal days.
I would have to say “Nope”. Because once you set an Object to “nil” it becomes… well… nil. It “IS” no longer an Object… it is Nothing… however, it wouldn’t throw an exception, because the the variable is still declared, it is just set to nothing. “IS”, is the key here. Because you’re doing a test to see what the object is. Like checking for a “Sender” in a command click. You can call a command button click from anywhere in your code… however, if you do a test to see if the Sender “IS” a TButton object, the code inside the TButton block will not run.
See my screen shot below:
This must be a special path in the compiler but it surprised me because it didn’t dereference a nil somewhere internally and cause an AV. I expected an access violation, as I didn’t believe that it was safe to check nil is. In fact, as other commenters stated, some other non-TObject types are NOT safe to use “is X” unless you know it’s not null.
In code review I would always insist on “if Assigned(x) and (x is TSomething)” because of these crashes.
W
It’s interesting topic 🙂 and I experimented little bit more. Actually when type of variable and IS class are the same – generated code for is operator is always just check for nil – if it’s not nil then compiler suppose it’s instance of given class, doesnt check actually with IsClass or for valid pointer and thats why it doesnt raise AV. Actually generated code for “if S is TSimpleRWSync” and “if Assigned(S)” is exactly the same – just check for nil. The optimization is not special for TObject, but for any class.
I was correct that it would not be an access violation and that ‘NOPE’ would be displayed. So S is still a variable but just contains nothing. If you comment out S:=NIL; you will see NOPE again because it exists but does not contain anything to reference.