-1

It may not be relevant, but I recently re-installed Delphi XE2.

I have a variable path (of type TPath, a TMS Gogole maps thing, although I doubt that that is important).

I halt in the debugger and evaluate path, which evaluates as Nil.

If I run, I am getting an exception, Read of address 0, which I suspect to be because of this.

When I then evaluate Assigned(path) at the same time that path = Nil it evolutes to True (same result when I stop on the ShowMessage line - which is executed)).

Can someone explain that to me?

Clean & rebuild changes nothing. Might it be better to remove & reinstall Delphi?

(apologies to @mbratch , I used var for demo, the real name is actully path)


[Update] Full code sample as provided by TMS and working for them (in a different tiem zone, which is why I ask here too).

This was retested here with:

 uses
   uwebgmapspolylines;

 procedure TForm1.FormCreate(Sender: TObject);
 var
   p: TPath;
 begin
   p := TPath.Create;

   if Assigned(p) then
     ShowMessage('creation OK');
 end;

and this proves the correct creation of TPath returns a valid instance.

When I stop at if Assigned(p) then and evaluate p I get Nil, but when I evaluate Assigned(p) I get True.

When I hover the cursor over the variable declaration in the IDE, shows that the type is declared in UWebGMapsPolyLines


[Futher update] Two votes to close? Seriously? I guess from folks who think that this just can't be - and yet it is!!!

The strange thing is that @j tried it and got p <> Nil. However, I tried it on a second PC and still get p = Nil using the code posted here, which was provided by TMS.

I admit that it seems strange, but I can reproduce it on 2 PCs. P is Nil and yet it is Assigned().

I don't have the code of Assigend() to step into. Also, I changed the code slightly to explicitly if System.Assigned(p) and still got the same result. Any suggestions?

Assigned, or not?

Mawg says reinstate Monica
  • 38,334
  • 103
  • 306
  • 551
  • 1
    The variable is actually called `var`? Isn't `var` a Delphi (Pascal) keyword? – lurker Jun 10 '13 at 02:06
  • 1
    So you have any `with` statements that may be confusing the debugger? – Gerry Coll Jun 10 '13 at 02:41
  • 1
    Can you edit your post to show your actual code? With that we should be able to figure out what's going on. – Mason Wheeler Jun 10 '13 at 02:52
  • 1
    What does `p` look like if you stop the debugger on the `ShowMessage` (which I assume is executed if `Assigned(p)` is `true`)? – lurker Jun 10 '13 at 03:06
  • Are you sure the compiler isn't removing the "impossible" condition - as the only way for p to equal nil would be if an exception occurs in its constructor, in which case the code wouldn't reach the `if Assigned...`. – Gerry Coll Jun 10 '13 at 04:26
  • Very hard to believe this is the case. Assigned implementation is known to be correct. – David Heffernan Jun 10 '13 at 06:38
  • @Gerry The compiler never does optimisations like that – David Heffernan Jun 10 '13 at 06:39
  • Try to trace into the `Assigned` method. I presume it is a different one from `System.Assigned` (use the Delphi built-in CPU debugger if you don't have the source for this particular `Assigned` method). – Jeroen Wiert Pluimers Jun 10 '13 at 08:06
  • Do you have the source of the component? Perhaps the constructor calls `Free()` if something goes wrong during the initialization. – iMan Biglari Jun 10 '13 at 09:46
  • 1
    @iManBiglari Perhaps? When a constructor raises an exception, the framework calls `Destroy` on the partially constructed object. But if that happens, the code never reaches `if Assigned`. – David Heffernan Jun 10 '13 at 11:31
  • @DavidHeffernan What if the constructor doesn't raise an exception, and instead calls `Free()` itself? I know this is a very bad practice, but it's a possibility. – iMan Biglari Jun 10 '13 at 11:40
  • 1
    @iManBiglari That would be insane, but it would not influence `Assigned`. It's a common mistake to think that when an object is freed that `Assigned()` returns `False`. I offer an answer of mine as a guide to this topic: http://stackoverflow.com/questions/8548843/why-should-i-not-use-if-assigned-before-using-or-freeing-things/8550628#8550628 – David Heffernan Jun 10 '13 at 11:42
  • 1
    RE, your picture: The items in the parenthesis in the local variables panel are *fields* of the corresponding object. Your *p* there has only one field and that's nil. For an unassigned *p*, the debugger will refuse to resolve the fields with the note *inaccessible value*. – Sertac Akyuz Jun 11 '13 at 01:35

1 Answers1

2

I used exactly your code (with Delphi XE2) and found this :

TPath breakpoint

TPath watch

Are you perhaps confusing FOwner = nil for p = nil? TPath inherits from TPersistent so you can pass it an owner (although it is optional to do so). You could, for example, do :

 p := TPath.Create(self);

EDIT

Try this :

   var p:TPath
   begin
*1   if assigned(p) then ShowMessage('foo');
     p:=nil;
     if assigned(p) then ShowMessage('bar');
     p:=TPath.Create;
     if assigned (p) then ShowMessage('ok');
   end;

Put your breakpoint on *1- you should see in a watch or local variable window :

 p       *Inaccessible Value*

Local variables for non reference-counted reference types are not initialized to zero/nil - they contain whatever random data happened to be in the space allocated to them. 'Inaccessible Value' means that whatever that random data is, it does not point to a readable memory address in your program's memory space.

Step to the next line -- > 'foo' --> if assigned(p)...

You see the message...why?! Assigned only checks for nil - since the local variable is not initialized, Assigned returns true (it does not know that you have given it an uninitialized local variable - it only knows you gave it something not nil). This is also why it is a bad idea to free an uninitialized local variable.

Step to the next line -- > p := nil --> if assigned(p)...

When you step past p:=nil you should see that Inaccessible Value changes to :

 p       nil

And you will not see the message 'bar' (remember, assigned(p) only checks for nil). Note that nil is naked in the watch - no parentheses! Stepping through to the end you see p's value change again in the watch after it has been created :

 p       (nil)     

Like Sertac explained in comments, when an object has been created the watch/locals windows show you their member contents in parentheses. The above shows us that p is not nil (without parentheses), it is not uninitialized (ie:not inaccessible value), and that it also contains a member field (expanding shows it is FOwner) that has been initialized to nil and has not been assigned a value.

The short lesson is that Assigned is only really useful for Fields or globals and not for non-reference-counted local variables - the former are initialized to nil when an object is created, the latter are not (when you enter a method).

J...
  • 30,968
  • 6
  • 66
  • 143
  • +1 You may well be onto something here. When I use your suggestion, `p := TPath.Create(self);` p does have a non-Nil value. I will request clarification, since they sent me the code sample with no parameter. Thanks, I imagine that I will award you the answer after they reply. – Mawg says reinstate Monica Jun 10 '13 at 23:12
  • @Mawg - But what are you seeing when you say "It evaluates to nil"? Do you see all of those items as I've posted above? A `TPath` is an object with many items in it(here we see an FItemPath, FItems, FUpdateCount, FNext, etc). Here the TPath is created just fine (ie: is not nil) - only that its FOwner field is `nil`. `p` itself can be non-nil and still have fields within it that are `nil` - clearly this is what `IfAssigned(p)` is telling you when it returns true. There is no need to assign FOwner for `p` if you don't need it (FOwner = nil is OK)-it also doesn't mean that `p` itself is `nil`. – J... Jun 10 '13 at 23:18
  • 1
    @Mawg I'll add that I have no idea why your watch only shows (nil) and mine shows more objects - maybe we have different versions of the TMS component (I just downloaded the demo from their site). I'm not aware of any options in delphi to change the behaviour of what is and is not reported in the locals window (maybe you don't have all the XE2 updates? Starter version?) – J... Jun 11 '13 at 08:48