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.
Related
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.
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.
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.
I'm working on a simple localization effort in D2010. I'm handling all strings on forms because ETM seems like overkill for my needs, as did other 3rd party tools... (although I'm not so sure at this point!)
Is the code below for changing the Const.pas strings considered safe to change the button labels on standard message boxes?
procedure HookResourceString(rs: PResStringRec; newStr: PChar);
var
oldprotect: DWORD;
begin
VirtualProtect(rs, SizeOf(rs^), PAGE_EXECUTE_READWRITE, #oldProtect);
rs^.Identifier := Integer(newStr);
VirtualProtect(rs, SizeOf(rs^), oldProtect, #oldProtect);
end;
const
NewOK: PChar = 'New Ok';
NewCancel: PChar = 'New Cancel';
Procedure TForm.FormCreate;
begin
HookResourceString(#SMsgDlgOK, NewOK);
HookResourceString(#SMsgDlgCancel, NewCancel);
end;
Yes, it should be fine, but I have some comments:
Make sure to call your HookResourceString function from only one thread at a time. If two threads call it simultaneously, you could end up restoring the wrong permissions.
Also for multithreading, make sure you don't use this code at a time when some other thread might be attempting to load a resourcestring. LoadResString reads the Identifier field twice, and it needs to have the same value both times.
There's no need to declare the new values as typed constants. Ordinary true constants are fine. (The compiler knows they need to be PChars because they're passed as actual arguments for a PChar parameter.)
Why not use dxgettext? It's open source, so you could at least take a look at how they do it...
http://dxgettext.po.dk/
Consider the following scenario:
type
PStructureForSomeCDLL = ^TStructureForSomeCDLL;
TStructureForSomeCDLL = record
pName: PAnsiChar;
end
function FillStructureForDLL: PStructureForSomeDLL;
begin
New(Result);
// Result.pName := PAnsiChar(SomeObject.SomeString); // Old D7 code working all right
Result.pName := Utf8ToAnsi(UTF8Encode(SomeObject.SomeString)); // New problematic unicode version
end;
...code to pass FillStructureForDLL to DLL...
The problem in unicode version is that the string conversion involved now returns a new string on stack and that's reclaimed at the end of the FillStructureForDLL call, leaving the DLL with corrupted data. In old D7 code, there were no intermediate conversion funcs and thus no problem.
My current solution is a converter function like below, which is IMO too much of an hack. Is there a more elegant way of achieving the same result?
var gKeepStrings: array of AnsiString;
{ Convert the given Unicode value S to ANSI and increase the ref. count
of it so that returned pointer stays valid }
function ConvertToPAnsiChar(const S: string): PAnsiChar;
var temp: AnsiString;
begin
SetLength(gKeepStrings, Length(gKeepStrings) + 1);
temp := Utf8ToAnsi(UTF8Encode(S));
gKeepStrings[High(gKeepStrings)] := temp; // keeps the resulting pointer valid
// by incresing the ref. count of temp.
Result := PAnsiChar(temp);
end;
One way might be to tackle the problem before it becomes a problem, by which I mean adapt the class of SomeObject to maintain an ANSI Encoded version of SomeString (ANSISomeString?) for you alongside the original SomeString, keeping the two in step in a "setter" for the SomeString property (using the same UTF8 > ANSI conversion you are already doing).
In non-Unicode versions of the compiler make ANSISomeString be simply a "copy" of SomeString string, which will of course not be a copy, merely an additional ref count on SomeString. In the Unicode version it references a separate ANSI encoding with the same "lifetime" as the original SomeString.
procedure TSomeObjectClass.SetSomeString(const aValue: String);
begin
fSomeString := aValue;
{$ifdef UNICODE}
fANSISomeString := Utf8ToAnsi(UTF8Encode(aValue));
{$else}
fANSISomeString := fSomeString;
{$endif}
end;
In your FillStructure... function, simply change your code to refer to the ANSISomeString property - this then is entirely independent of whether compiling for Unicode or not.
function FillStructureForDLL: PStructureForSomeDLL;
begin
New(Result);
result.pName := PANSIChar(SomeObject.ANSISomeString);
end;
There are at least three ways to do this.
You could change SomeObject's class
definition to use an AnsiString
instead of a string.
You could
use a conversion system to hold
references, like in your example.
You could initialize result.pname
with GetMem and copy the result of the
conversion to result.pname^ with
Move. Just remember to FreeMem it
when you're done.
Unfortunately, none of them is a perfect solution. So take a look at the options and decide which one works best for you.
Hopefully you already have code in your application to properly dispose off of all the dynamically allocated records that you New() in FillStructureForDLL(). I consider this code highly dubious, but let's assume this is reduced code to demonstrate the problem only. Anyway, the DLL you pass the record instance to does not care how big the chunk of memory is, it will only get a pointer to it anyway. So you are free to increase the size of the record to make place for the Pascal string that is now a temporary instance on the stack in the Unicode version:
type
PStructureForSomeCDLL = ^TStructureForSomeCDLL;
TStructureForSomeCDLL = record
pName: PAnsiChar;
// ... other parts of the record
pNameBuffer: string;
end;
And the function:
function FillStructureForDLL: PStructureForSomeDLL;
begin
New(Result);
// there may be a bug here, can't test on the Mac... idea should be clear
Result.pNameBuffer := Utf8ToAnsi(UTF8Encode(SomeObject.SomeString));
Result.pName := Result.pNameBuffer;
end;
BTW: You wouldn't even have that problem if the record passed to the DLL was a stack variable in the procedure or function that calls the DLL function. In that case the temporary string buffers will only be necessary in the Unicode version if more than one PAnsiChar has to be passed (the conversion calls would otherwise reuse the temporary string). Consider changing the code accordingly.
Edit:
You write in a comment:
This would be best solution if modifying the DLL structures were an option.
Are you sure you can't use this solution? The point is that from the POV of the DLL the structure isn't modified at all. Maybe I didn't make myself clear, but the DLL will not care whether a structure passed to it is exactly what it is declared to be. It will be passed a pointer to the structure, and this pointer needs to point to a block of memory that is at least as large as the structure, and needs to have the same memory layout. However, it can be a block of memory that is larger than the original structure, and contain additional data.
This is actually used in quite a lot of places in the Windows API. Did you ever wonder why there are structures in the Windows API that contain as the first thing an ordinal value giving the size of the structure? It's the key to API evolution while preserving backwards compatibility. Whenever new information is needed for the API function to work it is simply appended to the existing structure, and a new version of the structure is declared. Note that the memory layout of older versions of the structure is preserved. Old clients of the DLL can still call the new function, which will use the size member of the structure to determine which API version is called.
In your case no different versions of the structure exist as far as the DLL is concerned. However, you are free to declare it larger for your application than it really is, provided the memory layout of the real structure is preserved, and additional data is only appended. The only case where this wouldn't work is when the last part of the structure were a record with varying size, kind of like the Windows BITMAP structure - a fixed header and dynamic data. However, your record looks like it has a fixed length.
Wouldn't PChar(AnsiString(SomeObject.SomeString)) work?