views:

876

answers:

4

This code in a GUI application compiles and runs:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Self := TForm1.Create(Owner);
end;

(tested with Delphi 6 and 2009)

  • why is Self writable and not read-only?
  • in which situations could this be useful?

Edit:

  • is this also possible in Delphi Prism? (I think yes it is, see here)

Update: Delphi applications/libraries which make use of Self assignment:

+5  A: 

Maybe to allow passing to const or var parameters?

It could be an artefact, since system doesn't have self anywhere on the left of := sign.

Marco van de Voort
For passing self as const no special allowance is needed, for that Self can be const too. Passing it as a Var parameter is just another form of assigning, the question remains.
Henk Holterman
@Henk Holterman: Maybe it is just for convenience: Imagine that there is a function (from some library) that requires an object reference as a var parameter even though you might know that it does not actually change it. If self was not assignable, you would have to declare an additional variable, assign self to it and pass that variable. Since self is assignable you can just pass self to the function.
dummzeuch
+2  A: 

In reality, "Self" is just a name reference to a place on the stack that store address pointing to object in the heap. Forcing read-only on this variable is possible, apparently the designer decided not to. I believe the decision is arbitrary.

Can't see any case where this is useful, that'd merely change a value in stack. Also, changing this value can be dangerous as there is no guarantee that the behavior of the code that reference instance's member will be consistence across compiler versions.

Updated: In response to PatrickvL comment

The 'variable' "Self" is not on the stack (to my knowledge, it never is); Instead it's value is put in a register (EAX to be exact) just before a call to any object method is made. –

Nope, Self has actual address on the memory. Try this code to see for yourself.

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(IntToStr(Integer(@Self)));
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  newform: TForm;
  p: ^Integer;
begin
  Self.Caption := 'TheOriginal';
  newform := TForm.Create(nil);
  try
    newform.Caption := 'TheNewOne';
    // The following two lines is, technically, the same as
    //   Self := newform;
    p := Pointer(@Self);
    p^ := Integer(newform);
    ShowMessage(Self.Caption);  // This will show 'TheNewOne' instead of 'TheOriginal'
  finally
    Self.Free; // Relax, this will free TheNewOne rather than TheOriginal
  end;
end;
Sake
Changing a value in the stack could be dangerous - what will happen to the old object instance? Memory Leaking I guess.
mjustin
@mjustin: No problem with changing the stack value, it is just a reference (pointer) to the object, the calling code / the owner would still have the reference to finally free the object.
mghie
Self is implemented as an ordinary object reference, to ordinary even as this question shows.
Henk Holterman
It's not a "by convention" name. It's built into the language. You can't choose to go against the convention use a different name in your own programs.
Rob Kennedy
You were right, I mis-use the term. fixed.
Sake
The 'variable' "Self" is *not* on the stack (to my knowledge, it never is); Instead it's value is put in a register (EAX to be exact) just before a call to any object method is made.
PatrickvL
@PatrickvL: See my updated answer.
Sake
Hm, SO lost my previous comment, but you're wrong. Just ignore the @Self test and look at the disassembly of "Self := nil", it'll become something like "xor eax,eax"
PatrickvL
It should be called optimization. Yes, most of the time "Self" is does not stored in the stack. But I believe it's fair to make assumption that it's on the stack, since compiler will always make it look so.
Sake
+8  A: 

That's not as bad as it could be. I just tested it in Delphi 2009, and it would seem that, while the Self parameter doesn't use const semantics, which you seem to be implying it should, it also doesn't use var semantics, so you can change it all you want within your method without actually losing the reference the caller holds to your object. That would be a very bad thing.

As for the reason why, one of two answers. Either a simple oversight, or what Marco suggested: to allow you to pass Self to a var parameter.

Mason Wheeler
A: 

Sometimes, when you want to optimize a method for as far as you can take it (without resorting to assembly), 'Self' can be (ab)used as a 'free' variable - it could just mean the difference between using stack and using registers.

Sure, the contents of the stack are most probably already present in the CPU cache, so it should be fast to access, but registers are even faster still.

As a sidenote : I'm still missing the days when I was programming on the Amiga's Motorola 68000 and had the luxury of 16 data and 16 address registers.... I can't believe the world chose to go with the limited 4 registers of the 80x86 line of processors!

And as a final note, I choose to use Self sometimes, as the Delphi's optimizer is, well, not optimizing that well, actually. (At least, it pales compared to what trickery one can find in the various LLVM optimizers for example.) IMHO, and YMMV of course.

PatrickvL