Delphi Custom Component Knowing Which Referee Called A Method - delphi

I have created a custom component which has a property that the user can assign to another custom component..
TComp1 = class(TComponent)
public
property Comp2: TComp2 read GetComp2 write SetComp2;
property Something;
end;
TComp2 = class(TComponent)
public
procedure DoSomething;
end;
There could be multiple TComp1 components that assign the same TComp2. I need TComp2 to know which TComp1 called it because it needs to reference property "something" of that specific referee..
var
comp1a, comp1b: TComp1;
comp2: TComp2;
comp2 := TComp2.create;
comp1a := TComp1.create;
comp1b := TComp1.create;
comp1a.comp2 := comp2;
comp1b.comp2 := comp2;
comp1b.comp2.dosomething; <-- needs to know this was from comp1b not comp1a
obviously, the code above is just to illustrate my point and is not including the notification mechanisms that I have to put in place, etc.
so far, I have considered using the getter for TComp1.Comp2 to set an "activeComponent" property on the assigned TComp2 so that TComp2 can use that property to get the right component. While this should work, I believe it is unsafe and if someone tries to use comp2 directly or passes the reference to another variable entirely (comp := comp1a.comp2; comp.dosomething;), or tries to use it from multiple threads, there could be issues.
has anybody else encountered this issue? what is the best solution?
I hope somebody will be able to help :)

In the line:
comp1b.comp2.dosomething; <-- needs to know this was from comp1b not comp1a
The call to doSomething has absolutely no knowledge of comp1b. You should think of this as two separate lines of code:
LocalComp2 := comp1b.comp2;
LocalComp2.doSomething;
So as per David's comment, you need to pass the other component as a parameter. I.e.
comp1b.comp2.doSomething(comp1b);
This, by the way, is a stock-standard technique used throughout Delphi code. The best example is TNotifyEvent = procedure (Sender: TObject) of object; and is used in calls like:
ButtonClick(Self);
MenuItemClick(MainMenu);
You ask in a comment:
I have thought about that too but it seems somewhat redundant to effectively reference the same component twice.. comp1a.comp2.domsomething(comp1a); is there no better way?
As I said, the bit comp2.domsomething has no knowledge of the comp1a. just before it. So as far as the compiler is concerned it's not redundant. In fact it's also possible to call comp1a.comp2.domsomething(SomeOtherComponent).
However, that said, there is a better way.
Currently your code violates a princple called the Law of Demeter. Users of TComp1 are exposed to details abobut TComp2 even if they don't care about TComp2. This means that you can find yourself repeatedly writing:
comp1a.comp2.doSomething(comp1a);
comp1b.comp2.doSomething(comp1b);
comp1a.comp2.doSomething(comp1a);
comp1c.comp2.doSomething(comp1c);
To avoid that, fix the Law of Demeter violation by writing:
procedure TComp1.doSomething;
begin
comp2.doSomething(Self);
end;
Now your earlier lines become:
comp1a.doSomething;
comp1b.doSomething;
comp1a.doSomething;
comp1c.doSomething;

The obvious solution is to pass the extra information as a parameter. Like this:
comp1b.comp2.dosomething(comp1b);
Expecting comp2 to be able to work out whether it was referenced from comp1a or comp1b is unrealistic, and frankly would be an indication of a poor design.
Parameters are explicit and so demonstrate clear intent to the reader.

Related

Why does FreeAndNil sets nil before freeing the object? [duplicate]

If you will look at the code of FreeAndNil procedure you will see:
procedure FreeAndNil(var Obj);
var
Temp: TObject;
begin
Temp := TObject(Obj);
Pointer(Obj) := nil;
Temp.Free;
end;
What is the reason they assigning Nil to an object reference and only after this destroying it? Why not vice-versa?
I can think of two reasons for doing it this way round, neither of which seems at all compelling.
Reason 1: to guarantee that the reference is set to nil in case an exception is raised
The implementation achieves this. If the destructor raises, then the reference is still set to nil. Another way to do so would be with a finally block:
try
TObject(Obj).Free;
finally
TObject(Obj) := nil;
end;
The downside of this is performance. Particularly on x86 a try/finally is a little expensive. In such a fundamental routine it is prudent to avoid this expense.
Why do I find the desire to nil at all costs not to be compelling? Well, as soon as destructor start failing you may as well give up. You can no longer reason clearly about your program's state. You cannot tell what failed and what state your program is in. It is my view that the correct course of action in the face of a destructor that raises is to terminate the process.
Reason 2: to ensure that other threads can detect that the object is being destroyed
Again this is achieved but it is of no practical use. Yes you can test whether the reference is assigned or not. But then what? The other thread cannot call methods on the object without synchronization. All you could do is learn whether or not the object is alive. And if that is so, why would it matter if this status changed before or after the destructor runs?
So whilst I present this as a possible reason I cannot believe that anyone in Embarcadero was really swayed by this argument.
There's a variation on David's second reason that is a little more compelling. Although one might argue that if it applies there are other problems that should be fixed.
Reason 3: to ensure event handlers on the same thread can detect that the object is being destroyed
Here's a concocted hypothetical example:
TOwner.HandleCallback;
begin
if Assigned(FChild) then
FChild.DoSomething;
end;
TChildClass.Destroy;
begin
if Assigned(FOnCallback) then FOnCallback;
inherited Destroy;
end;
Now if TOwner calls:
FChild.Free;
FChild := nil;
FChild will be asked to DoSomething in the middle of its destruction cycle. A certain recipe for disaster. The implementation of FreeAndNil neatly avoids this.
Yes you may argue that firing callback events during destruction is dangerous, but it does have its benefits. There are quite few examples in Delphi/VCL code. Especially if you expand the scope of concern to include calling polymorphic methods - which also put aspects of the destruction sequence outside of your control.
Now I must point out that I'm not aware of any specifc cases in Delphi library code where this problem could manifest. But there are some complex circular dependencies in parts of the VCL. So I wouldn't be surprised if changing the implementation to the more obvious choice in SysUtils leads to a few unpleasant surprises.
The only thing that really bothered me for years is that FreeAndNil(var obj) lacks type safety. I know that due to the lack of adequate language support there was simply no way to do it right, but since we have generics for a while, here's a quick and simple tool that can make your life easier.
type
TypeSafe = class sealed
public
class procedure FreeAndNil<T : class>( var obj : T); static; inline;
end;
class procedure TypeSafe.FreeAndNil<T>( var obj : T);
begin
SysUtils.FreeAndNil( obj);
end;
If you add an overload for the normal FreeAndNil(var Obj) and mark it as deprecatedyou got a fair chance to find all the places where someone hands over an interface pointer to it -- and if the code base is only large enough you will find interesting things, believe me.
procedure FreeAndNil(var Obj); inline; deprecated 'use TypeSafe.FreeAndNil<T>() instead';
Note that you don't even have to specify the <T>since the compiler is smart enough to find out the right type for you. Just add the unit on top and change all
FreeAndNil(foobar);
in your source code into
TypeSafe.FreeAndNil(foobar);
and you're done.

Why FreeAndNil implementation doing Nil before Free?

If you will look at the code of FreeAndNil procedure you will see:
procedure FreeAndNil(var Obj);
var
Temp: TObject;
begin
Temp := TObject(Obj);
Pointer(Obj) := nil;
Temp.Free;
end;
What is the reason they assigning Nil to an object reference and only after this destroying it? Why not vice-versa?
I can think of two reasons for doing it this way round, neither of which seems at all compelling.
Reason 1: to guarantee that the reference is set to nil in case an exception is raised
The implementation achieves this. If the destructor raises, then the reference is still set to nil. Another way to do so would be with a finally block:
try
TObject(Obj).Free;
finally
TObject(Obj) := nil;
end;
The downside of this is performance. Particularly on x86 a try/finally is a little expensive. In such a fundamental routine it is prudent to avoid this expense.
Why do I find the desire to nil at all costs not to be compelling? Well, as soon as destructor start failing you may as well give up. You can no longer reason clearly about your program's state. You cannot tell what failed and what state your program is in. It is my view that the correct course of action in the face of a destructor that raises is to terminate the process.
Reason 2: to ensure that other threads can detect that the object is being destroyed
Again this is achieved but it is of no practical use. Yes you can test whether the reference is assigned or not. But then what? The other thread cannot call methods on the object without synchronization. All you could do is learn whether or not the object is alive. And if that is so, why would it matter if this status changed before or after the destructor runs?
So whilst I present this as a possible reason I cannot believe that anyone in Embarcadero was really swayed by this argument.
There's a variation on David's second reason that is a little more compelling. Although one might argue that if it applies there are other problems that should be fixed.
Reason 3: to ensure event handlers on the same thread can detect that the object is being destroyed
Here's a concocted hypothetical example:
TOwner.HandleCallback;
begin
if Assigned(FChild) then
FChild.DoSomething;
end;
TChildClass.Destroy;
begin
if Assigned(FOnCallback) then FOnCallback;
inherited Destroy;
end;
Now if TOwner calls:
FChild.Free;
FChild := nil;
FChild will be asked to DoSomething in the middle of its destruction cycle. A certain recipe for disaster. The implementation of FreeAndNil neatly avoids this.
Yes you may argue that firing callback events during destruction is dangerous, but it does have its benefits. There are quite few examples in Delphi/VCL code. Especially if you expand the scope of concern to include calling polymorphic methods - which also put aspects of the destruction sequence outside of your control.
Now I must point out that I'm not aware of any specifc cases in Delphi library code where this problem could manifest. But there are some complex circular dependencies in parts of the VCL. So I wouldn't be surprised if changing the implementation to the more obvious choice in SysUtils leads to a few unpleasant surprises.
The only thing that really bothered me for years is that FreeAndNil(var obj) lacks type safety. I know that due to the lack of adequate language support there was simply no way to do it right, but since we have generics for a while, here's a quick and simple tool that can make your life easier.
type
TypeSafe = class sealed
public
class procedure FreeAndNil<T : class>( var obj : T); static; inline;
end;
class procedure TypeSafe.FreeAndNil<T>( var obj : T);
begin
SysUtils.FreeAndNil( obj);
end;
If you add an overload for the normal FreeAndNil(var Obj) and mark it as deprecatedyou got a fair chance to find all the places where someone hands over an interface pointer to it -- and if the code base is only large enough you will find interesting things, believe me.
procedure FreeAndNil(var Obj); inline; deprecated 'use TypeSafe.FreeAndNil<T>() instead';
Note that you don't even have to specify the <T>since the compiler is smart enough to find out the right type for you. Just add the unit on top and change all
FreeAndNil(foobar);
in your source code into
TypeSafe.FreeAndNil(foobar);
and you're done.

Access Violation when handling forms

I have procedure to show/hide one element on TForm like that:
procedure ShowHideControl(const ParentForm: TForm; const ControlName: String; ShowControl: Boolean);
var
i: Integer;
begin
for i := 0 to pred(ParentForm.ComponentCount) do
begin
if (ParentForm.Components[i].Name = ControlName) then
begin
if ShowControl then
TControl(ParentForm.Components[i]).Show
else
TControl(ParentForm.Components[i]).Hide;
Break;
end;
end;
end;
then I try to use it like:
procedure TForm1.Button6Click(Sender: TObject);
begin
ShowHideEveryControl(TForm(TForm1), 'Button4', True);
end;
Why do I get Access Violation on Button6 click?
For me everything is OK... Button4 exists as a child :)
This cast is wrong:
TForm(TForm1)
You are telling the compiler to ignore the fact that TForm1 is not a TForm instance, and asking it to pretend that it is. That is fine until you actually try to use it as an instance, and then the error occurs.
You need to pass a real instance to a TForm descendent. You can write it like this:
ShowHideEveryThing(Self, 'Button4', True);
Just in case you are not clear on this, the parameter of your procedure is of type TForm. That means you need to supply an instance of a class that either is, or derives from TForm. I repeat, you must supply an instance. But you supply TForm1 which is a class.
And then the next problem comes here:
if (ParentForm.Components[i].Name = FormName) then
begin
if ShowForm then
TForm(ParentForm.Components[i]).Show
else
TForm(ParentForm.Components[i]).Hide;
Break;
end;
Again you have used an erroneous cast. When the compiler tells you that it a particular object does not have a method, you must listen to it. It's no good telling the compiler to shut up and pretend that an object of one type is really an object of a different type. Your button is categorically not a form, so don't try to cast it to TForm.
It is very hard to know what you are actually trying to do here. When you write:
ShowHideEveryThing(Self, 'Button4', True);
It would seem to me to me more sensible to write:
Button4.Show;
It is not a good idea to refer to controls using their names represented as text. It is much safer and cleaner to refer to them using reference variables. That way you let the compiler do its job and check the type safety of your program.
The names used in your function are suspect:
procedure ShowHideEveryThing(const ParentForm: TForm; const FormName: String;
ShowForm: Boolean);
Let's look at them:
ShowHideEveryThing: but you claim that the function should show/hide one element. That does not tally with the use of everything.
FormName: you actually pass a component name, and then look for components owned by ParentForm that have that name. It seems that FormName is wrong.
ShowForm: again, do you want to control visibility of the form, or a single element?
Clearly you need to step back and be clear on the intent of this function.
As an aside, you should generally never need to write:
if b then
Control.Show
else
Control.Hide;
Instead you can write:
Control.Visible := b;
My number one piece of advice to you though is to stop casting until you understand it properly. Once you understand it properly, design your code if at all possible so that you don't need to cast. If you ever really do need to cast, make sure that your cast is valid, ideally by using a checked cast with the as operator. Or at least testing first with the is operator.
Your code shows all the hallmarks of a classic mistake. The compiler objects to the code that you write. You have learnt from somewhere that casting can be used to suppress these compiler errors and now you apply this technique widely as a means to make your program compile. The problem is that the compiler invariably knows what it is talking about. When it objects, listen to it. If ever you find yourself suppressing a compiler error with a cast, take a step back and think carefully about what you are doing. The compiler is your friend.

How to Start Creating My Own Classes with Delphi?

I posted a question a few days ago, and the answers told me to create my own classes.
I'm an old-school programmer from the pre-OOP days my programming is well structured, efficient and organized, but lacks in any custom OOPing other than using Delphi and 3rd party objects.
I had looked at how Delphi's object oriented classes worked back when I started using Delphi 2, but they seemed foreign to my programming background. I understand how they were and are excellent for developers designing components and for visual controls on the user interface. But I never found the need to use them in the coding of my program itself.
So now I look again, 15 years later, at Delphi's classes and OOPing. If I take, for example, a structure that I have such as:
type
TPeopleIncluded = record
IndiPtr: pointer;
Relationship: string;
end;
var
PeopleIncluded: TList<TPeopleIncluded>;
Then an OOP advocator will probably tell me to make this a class. Logically, I would think this would be a class inherited from the generic TList. I would guess this would be done like this:
TPeopleIncluded<T: class> = class(TList<T>)
But that's where I get stuck, and don't have good instructions on how ot do the rest.
When I look at some class that Delphi has as an example in the Generics.Collections unit, I see:
TObjectList<T: class> = class(TList<T>)
private
FOwnsObjects: Boolean;
protected
procedure Notify(const Value: T; Action: TCollectionNotification); override;
public
constructor Create(AOwnsObjects: Boolean = True); overload;
constructor Create(const AComparer: IComparer<T>; AOwnsObjects: Boolean = True); overload;
constructor Create(Collection: TEnumerable<T>; AOwnsObjects: Boolean = True); overload;
property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;
end;
and then their definitions of the constructors and procedures are:
{ TObjectList<T> }
constructor TObjectList<T>.Create(AOwnsObjects: Boolean);
begin
inherited;
FOwnsObjects := AOwnsObjects;
end;
constructor TObjectList<T>.Create(const AComparer: IComparer<T>; AOwnsObjects: Boolean);
begin
inherited Create(AComparer);
FOwnsObjects := AOwnsObjects;
end;
constructor TObjectList<T>.Create(Collection: TEnumerable<T>; AOwnsObjects: Boolean);
begin
inherited Create(Collection);
FOwnsObjects := AOwnsObjects;
end;
procedure TObjectList<T>.Notify(const Value: T; Action: TCollectionNotification);
begin
inherited;
if OwnsObjects and (Action = cnRemoved) then
Value.Free;
end;
Let me tell you that this "simple" class definition may be obvious to those of you who have used OOP in Delphi for years, but to me it only provides me with hundreds of unanswered questions on what do I use and how do I use it.
To me, this does not appear to be a science. It appears to be an art of how to best structure your information into objects.
So this question, and I hope it doesn't get closed because I really need help with this, is where or how do I get the best instruction on using Delphi to create classes - and how to do it the proper Delphi way.
To me, this does not appear to be a science. It appears to be an art
of how to best structure your information into objects.
Well... Yeah. There really aren't a lot of formal requirements. It's really just a set of tools to help you organize your ideas, and eliminate a lot of duplication along the way.
Then an OOP advocator will probably tell me to make this a class. Logically, I would think this would be a class inherited from the generic TList.
Actually, the whole point of generic containers is that you don't have to make a new container class for each type of object. Instead, you'd make a new content class and then create a TList<TWhatever>.
Think of a class instance as a pointers to a record.
Now: why use a class when you could use a pointer to a record? A couple reasons:
encapsulation: You can hide some aspects of the implementation with the private keyword so that other developers (including your future self) know not to depend on implementation details that may change or that just aren't important to understanding the concept.
polymorphism: You can avoid a lot of special dispatch logic by giving each of your records a set of pointers to functions. Then, rather than having a large case statement where you do different things for each type of object, you loop through your list and send each object the same message, then it follows the function pointer to decide what to do.
inheritance: As you start making records with pointers to functions and procedures, you find that you often have cases where you need a new function-dispatch record that's very much like one you already have, except you need to change one or two of the procedures. Subclassing is just a handy way to make that happen.
So in your other post, you indicated that your overall program looks like this:
procedure PrintIndiEntry(JumpID: string);
var PeopleIncluded : TList<...>;
begin
PeopleIncluded := result_of_some_loop;
DoSomeProcess(PeopleIncluded);
end;
It's not clear to me what Indi or JumpID mean, so I'm going to pretend that your company does skydiving weddings, and that Indi means "individual" and JumpID is a primary key in a database, indicating a flight where all those individuals are in the wedding party and scheduled to jump out of the same plane... And it's vitally important to know their Relationship to the happy couple so that you can give them the right color parachute.
Obviously, that isn't going to match your domain exactly, but since you're asking a general question here, the details don't really matter.
What the people in the other post were trying to tell you (my guess anyway) wasn't to replace your list with a class, but to replace the JumpID with one.
In other words, rather than passing JumpID to a procedure and using that to fetch the list of people from a database, you create a Jump class.
And if your JumpID actually indicates a jump as in goto, then you'd probably actually a bunch of classes that all subclass the same thing, and override the same method in different ways.
In fact, let's assume that you do some parties that aren't weddings, and in that case, you don't need the Relationships, but only a simple list of people:
type TPassenger = record
FirstName, LastName: string;
end;
type TJump = class
private
JumpID : string;
manifest : TList< TPassenger >;
public
constructor Init( JumpID: string );
function GetManifest( ) : TList< TPassenger >;
procedure PrintManifest( ); virtual;
end;
So now PrintManifest() does the job of your PrintIndyEntry(), but instead of calculating the list inline, it calls Self.GetManifest().
Now maybe your database doesn't change much, and your TJump instance is always short lived, so you decide to just populate Self.manifest in the constructor. In that case, GetManifest() just returns that list.
Or maybe your database changes frequently, or the TJump sticks around long enough that the database may change underneath it. In that case, GetManifest() rebuilds the list each time it's called... Or perhaps you add another private value indicating the last time you queried, and only update after the information expires.
The point is that PrintManifest doesn't have to care how GetManifest works, because you've hidden that information away.
Of course, in Delphi, you could have done the same thing with a unit, hiding a list of cached passenger lists in your implementation section.
But clasess bring a little more to the table, when it comes time to implement the wedding-party-specific features:
type TWeddingGuest = record
public
passenger : TPassenger;
Relationship : string;
end;
type TWeddingJump = class ( TJump )
private
procedure GetWeddingManifest( ) : TList< TWeddingGuest >;
procedure PrintManifest( ); override;
end;
So here, the TWeddingJump inherits the Init and GetManifest from the TJump, but it also adds a GetWeddingManifest( );, and it's going to override the behavior of PrintManifest() with some custom implementation. (You know it's doing this because of the override marker here, which corresponds to the virtual marker in TJump.
But now, suppose that PrintManifest is actually a rather complicated procedure, and you don't want to duplicate all that code when all you want to do is add one column in the header, and another column in the body listing the relationship field. You can do that like so:
type TJump = class
// ... same as earlier, but add:
procedure PrintManfestHeader(); virtual;
procedure PrintManfiestRow(passenger:TPassenger); virtual;
end;
type TWeddingJump = class (TJump)
// ... same as earlier, but:
// * remove the PrintManifest override
// * add:
procedure PrintManfestHeader(); override;
procedure PrintManfiestRow(passenger:TPassenger); override;
end;
Now, you want to do this:
procedure TJump.PrintManifest( )
var passenger: TPassenger;
begin;
// ...
Self.PrintManifestHeader();
for guest in Self.GetManifest() do begin
Self.PrintManifestRow();
end;
// ...
end;
But you can't, yet, because GetManifest() returns TList< TPassenger >; and for TWeddingJump, you need it to return TList< TWeddingGuest >.
Well, how can you handle that?
In your original code, you have this:
IndiPtr: pointer
Pointer to what? My guess is that, just like this example, you have different types of individual, and you need them to do different things, so you just use a generic pointer, and let it point to different kinds of records, and hope you cast it to the right thing later. But classes give you several better ways to solve this problem:
You could make TPassenger a class and add a GetRelationship() method. This would eliminate the need for TWeddingGuest, but it means that GetRelationship method is always around, even when you're not talking about weddings.
You could add a GetRelationship(guest:TPassenger) in the TWeddingGuest class, and just call that inside TWeddingGuest.PrintManifestRow().
But suppose you have to query a database to populate that information. With the two methods above, you're issuing a new query for each passenger, and that might bog down your database. You really want to fetch everything in one pass, in GetManifest().
So, instead, you apply inheritance again:
type TPassenger = class
public
firstname, lastname: string;
end;
type TWeddingGuest = class (TPassenger)
public
relationship: string;
end;
Because GetManifest() returns a list of passengers, and all wedding guests are passengers, you can now do this:
type TWeddingJump = class (TJump)
// ... same as before, but:
// replace: procedure GetWeddingManfiest...
// with:
procedure GetManifest( ) : TList<TPassenger>; override;
// (remember to add the corresponding 'virtual' in TJump)
end;
And now, you fill in the details for TWeddingJump.PrintManifestRow, and the same version of PrintManifest works for both TJump and TWeddingJump.
There's still one problem: we declared PrintManifestRow(passenger:TPassenger) but we're actually passing in a TWeddingGuest. This is legal, because TWeddingGuest is a subclass of TPassenger... But we need to get at the .relationship field, and TPassenger doesn't have that field.
How can the compiler trust that inside a TWeddingJump, you're always going to pass in a TWeddingGuest rather than just an ordinary TPassenger? You have to assure it that the relationship field is actually there.
You can't just declare it as TWeddingJupmp.(passenger:TWeddingGuest) because by subclassing, you're basically promising to do all the things the parent class can do, and the parent class can handle any TPassenger.
So you could go back to checking the type by hand and casting it, just like an untyped pointer, but again, there are better ways to handle this:
Polymorphism approach: move the PrintManifestRow() method to the TPassenger class (removing the passenger:TPassenger parameter, as this is now the implicit parameter Self), override that method in TWeddingGuest, and then just have TJump.PrintManifest call passenger.PrintManifestRow().
Generic class approach: make TJump itself a generic class (type TJump<T:TPassenger> = class), and instead of having GetManifest() return a TList<TPassenger>, you have it return TList<T>. Likewise, PrintManifestRow(passenger:TPassenger) becomes PrintManifestRow(passenger:T);. Now you can say: TWeddingJump = class(TJump<TWeddingGuest>) and now you're free to declare the overridden version as PrintManifestRow(passenger:TWeddingGuest).
Anyway, that's way more than I expected to write about all this. I hope it helped. :)

Why is Self assignable in Delphi?

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:
python4delphi
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.
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.
Assigning to Self is so illogical and useless that this 'feature' is probably an oversight. And as with assignable constants, it's not always easy to correct such problems.
The simple advice here is: don't do it.
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;
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.

Resources