See, the developers of the Delphi compiler, nothing is impossible.
See, the developers of the Delphi compiler, nothing is impossible.
Originally shared by Maciej Izak
Hi,
I'm pleased to finally announce the additional record operators: Initialize, Finalize.
Download (r33200): http://svn.freepascal.org/svn/fpc/branches/maciej/smart_pointers
"Record management operators aka record constructor/destructor"
They working like low level auto-executed constructor/destructor for records.
===== motivation =====
It can be used for:
-nullable types
-very fast RTTI.TValue implementation
-as replacement for manually called Init/Finit record methods for example like in mORMot for many types.
-auto init/finit for fields of pointer/object type
Additionally, it is base for my further work:
-smart pointers
-ARC objects
-Oxygene mode
-Delphi NextGen mode
===== example begin =====
{$MODE DELPHI}
uses SysUtils;
type
TFoo = record
private
class operator Initialize(var aFoo: TFoo);
class operator Finalize(var aFoo: TFoo);
public
F: Integer;
S: string;
P: Pointer;
C: TObject
end;
class operator TFoo.Initialize(var aFoo: TFoo);
begin
aFoo.F := 10;
aFoo.S := 'FPC rulezzz';
aFoo.P := nil;
aFoo.C := nil;
end;
class operator TFoo.Finalize(var aFoo: TFoo);
begin
if aFoo.S = 'Delphi rulezzz' then
raise Exception.Create('Trololo');
FreeMem(aFoo.P);
aFoo.C.Free;
end;
procedure Foo;
var
f: TFoo;
begin
WriteLn(f.F); // output: 10
WriteLn(f.S); // output: FPC rulezzz
WriteLn(f.P = nil); // output: true
WriteLn(f.C = nil); // output: true
end;
begin
Foo;
end.
===== example end=====
===== more info =====
When Initialize of Finalize is used, record is treated as managed record (similar to record containg string, interface or dynamic array).
It works correctly in all possible ways, works for:
* New
* Dispose
* Initialize
* Finalize
* InitializeArray
* FinalizeArray
* global variables
* local variables
* for fields inside: records, objects, classes
===== additional gain =====
Speed of dynamically created instances for records increased. For now is used always init table instead of rtti table:
type
TBar = record
f1,f2,f3,f4,f5,f6,f7,f8,f9: byte;
s: string;
end;
previously:
GetMem(PB, SizeOf(TBar));
InitializeArray(PB, TypeInfo(TBar), 1); // FPC_INITIALIZE was executed 10 times
now:
GetMem(PB, SizeOf(TBar));
InitializeArray(PB, TypeInfo(TBar), 1); // FPC_INITIALIZE is executed just once
===== more examples =====
http://svn.freepascal.org/cgi-bin/viewvc.cgi/branches/maciej/smart_pointers/tests/test/toperator90.pp?view=co&revision=33200&content-type=text%2Fplain&pathrev=33200
http://svn.freepascal.org/cgi-bin/viewvc.cgi/branches/maciej/smart_pointers/tests/test/toperator91.pp?view=co&revision=33200&content-type=text%2Fplain&pathrev=33200
http://svn.freepascal.org/cgi-bin/viewvc.cgi/branches/maciej/smart_pointers/tests/test/toperator92.pp?view=co&content-type=text%2Fplain&pathrev=33200
http://svn.freepascal.org/cgi-bin/viewvc.cgi/branches/maciej/smart_pointers/tests/test/toperator93.pp?view=co&content-type=text%2Fplain&pathrev=33200
===== more details from commit message =====
http://svn.freepascal.org/cgi-bin/viewvc.cgi/branches/maciej/smart_pointers/?view=log&sortby=date&pathrev=33200
http://svn.freepascal.org/svn/fpc/branches/maciej/smart_pointers
Originally shared by Maciej Izak
Hi,
I'm pleased to finally announce the additional record operators: Initialize, Finalize.
Download (r33200): http://svn.freepascal.org/svn/fpc/branches/maciej/smart_pointers
"Record management operators aka record constructor/destructor"
They working like low level auto-executed constructor/destructor for records.
===== motivation =====
It can be used for:
-nullable types
-very fast RTTI.TValue implementation
-as replacement for manually called Init/Finit record methods for example like in mORMot for many types.
-auto init/finit for fields of pointer/object type
Additionally, it is base for my further work:
-smart pointers
-ARC objects
-Oxygene mode
-Delphi NextGen mode
===== example begin =====
{$MODE DELPHI}
uses SysUtils;
type
TFoo = record
private
class operator Initialize(var aFoo: TFoo);
class operator Finalize(var aFoo: TFoo);
public
F: Integer;
S: string;
P: Pointer;
C: TObject
end;
class operator TFoo.Initialize(var aFoo: TFoo);
begin
aFoo.F := 10;
aFoo.S := 'FPC rulezzz';
aFoo.P := nil;
aFoo.C := nil;
end;
class operator TFoo.Finalize(var aFoo: TFoo);
begin
if aFoo.S = 'Delphi rulezzz' then
raise Exception.Create('Trololo');
FreeMem(aFoo.P);
aFoo.C.Free;
end;
procedure Foo;
var
f: TFoo;
begin
WriteLn(f.F); // output: 10
WriteLn(f.S); // output: FPC rulezzz
WriteLn(f.P = nil); // output: true
WriteLn(f.C = nil); // output: true
end;
begin
Foo;
end.
===== example end=====
===== more info =====
When Initialize of Finalize is used, record is treated as managed record (similar to record containg string, interface or dynamic array).
It works correctly in all possible ways, works for:
* New
* Dispose
* Initialize
* Finalize
* InitializeArray
* FinalizeArray
* global variables
* local variables
* for fields inside: records, objects, classes
===== additional gain =====
Speed of dynamically created instances for records increased. For now is used always init table instead of rtti table:
type
TBar = record
f1,f2,f3,f4,f5,f6,f7,f8,f9: byte;
s: string;
end;
previously:
GetMem(PB, SizeOf(TBar));
InitializeArray(PB, TypeInfo(TBar), 1); // FPC_INITIALIZE was executed 10 times
now:
GetMem(PB, SizeOf(TBar));
InitializeArray(PB, TypeInfo(TBar), 1); // FPC_INITIALIZE is executed just once
===== more examples =====
http://svn.freepascal.org/cgi-bin/viewvc.cgi/branches/maciej/smart_pointers/tests/test/toperator90.pp?view=co&revision=33200&content-type=text%2Fplain&pathrev=33200
http://svn.freepascal.org/cgi-bin/viewvc.cgi/branches/maciej/smart_pointers/tests/test/toperator91.pp?view=co&revision=33200&content-type=text%2Fplain&pathrev=33200
http://svn.freepascal.org/cgi-bin/viewvc.cgi/branches/maciej/smart_pointers/tests/test/toperator92.pp?view=co&content-type=text%2Fplain&pathrev=33200
http://svn.freepascal.org/cgi-bin/viewvc.cgi/branches/maciej/smart_pointers/tests/test/toperator93.pp?view=co&content-type=text%2Fplain&pathrev=33200
===== more details from commit message =====
http://svn.freepascal.org/cgi-bin/viewvc.cgi/branches/maciej/smart_pointers/?view=log&sortby=date&pathrev=33200
http://svn.freepascal.org/svn/fpc/branches/maciej/smart_pointers
Smart pointers have been possible in Delphi for a long time
ReplyDeleteDavid Heffernan By anonymous methods. That is workaround - not really smart ;). Approach by using records is more lightweight. Anyway at the moment we don't have smart pointers in FPC. Initialize/Finalize is just small step in this direction.
ReplyDeleteMaciej Izak Not smart? Why not? C++ doesn't bake these into the language, they are implemented on top of the language.
ReplyDeleteOf course, smart pointers are much more important in C++ because of the RAII idiom. In C++ there is not try/finally so a different idiom is used to manage lifetime. Which means that smart pointers aren't as imperative for Delphi code.
David Heffernan There is no smart pointers in Delphi - in Delphi exist fat and slow smart pointer simulator. :) It is not smart because it means many useless additional calls, and memory consumption in comparison to C++ implementation (or FPC in near future). It will not be part of language (not at all) called smart pointers, just more proper approach for things called "smart pointers" (maybe with oxygene additional syntax sugar: unretained, weak, strong).
ReplyDeleteDavid Heffernan In addition it will be used for Delphi NEXTGEN mode (ARC) without breaking any compatibility for existing FPC code base and modes, unlike in Delphi NEXTGEN.
ReplyDeleteI can't quite bring myself to read all that source code. Perhaps what you say is true. Perhaps there's a real need for smart pointers that I am not aware of. Perhaps Delphi needs to adopt RAII.
ReplyDeleteOK, time to press the mute button
ReplyDeleteThe topic was not about smart pointers actually. It's about the records custom initializators/finalizators, which allow all kinds of useful things, not only smart pointers.
ReplyDeleteOne of most voted feature request in QC is request of THIS feature (http://qc.embarcadero.com/wc/qcmain.aspx?d=21729). 10 years. Your opinion is important for us (C) Bor/CG/Emb.
ReplyDeleteJavier Hernández Actually, Delphi has record constructors.
ReplyDeleteJavier Hernández Not that I am aware of.
ReplyDeleteUwe Raabe Javier Hernández the topic is not about record constructors/destructors but about management operators Initialize/Finalize which Delphi hasn't.
ReplyDeleteUwe Raabe You can't have a default constructor, though, nor a destructor. Initialise/Finalize as class operators here seem (to me) to be names that apply to what happens, but don't fit the Delphi way of things. In Delphi, I'd like to see record constructors and destructors - or removal of the constructor keyword from records completely and have something like 'initializer' 'finalizer' instead, so the way you'd have a class's 'constructor TFoo.Create' you might have 'initializer TFoo.Init'. But IMO it's simpler to keep the existing keywords, and have them function rather than introducing new operators or new keywords.
ReplyDeleteDavid Millington I find them highly descriptive and proper. After all thats what the compiler calls for you or that you call yourself if you have a dynamically allocated array of records. And they fit with the Inc, Round etc operators that can also be overloaded.
ReplyDeleteDavid Millington removing constructors from records is bad idea. "Constructor" is part of using "New" intrinsic. For example:
ReplyDeletetype
PR = ^TR;
TR = record
constructor Create(A: Integer);
end;
...
var
R: PR;
begin
R := New(PR, Create(10));