There will be a new interesting feature in the upcoming Delphi 10.3 Rio: inline declared variables. I have permission to blog a little about it.
Marco Cantù already wrote about this new feature. I am not going to explain it, as I think he already did a good job doing that.
I just want to demo one of the main advantages of them: they are block-local, i.e. they are initialized at the point of declaration and are finalized at the end of the begin
-end
block they were declared in. This means that an interface or other managed variable declared that way is finalized at the end of the block.
To demo this, I made a little talkative interface, which tells us what it is doing, and when it is being created and being destroyed. It also has a name. Here is the code:
type ITalking = interface procedure Talk; end; TTalking = class(TInterfacedObject, ITalking) private FName: string; public constructor Create(const Name: string); procedure Talk; destructor Destroy; override; end; implementation { TTalking } constructor TTalking.Create(const Name: string); begin FName := Name; Writeln(Format('Creating %s', [Name])); end; destructor TTalking.Destroy; begin Writeln(Format('Destroying %s', [FName])); inherited; end; procedure TTalking.Talk; begin Writeln(Format('Hi, %s talking here!', [FName])); end;
Demo
And here is the demo:
procedure Test; begin var I1: IInterface := TTalking.Create('One'); // one way to declare an interface Writeln('// Before block'); Writeln; begin Writeln('// Before first inline var...'); var I2 := TTalking.Create('Two') as ITalking; // the other way: type inference I2.Talk; var I3: ITalking := TTalking.Create('Three'); I3.Talk; Writeln('// Do something useful here'); end; Writeln; Writeln('// After block'); var I4: ITalking := TTalking.Create('Four'); Writeln('// After declaration of Four'); end;
And the output is:
Creating One // Before block // Before first inline var... Creating Two Hi, Two talking here! Creating Three Hi, Three talking here! // Do something useful here Destroying Three Destroying Two // After block Creating Four // After declaration of Four Destroying Four Destroying One
As you can see, the two interfaces declared and initialized inside the inner block are destroyed at the end of the same block. The interfaces declared and initialized in the outer block are destroyed at the end of the function.
This creates some interesting opportunities, e.g. for RAII using interfaces, or other auto-finalized structures. RAII doesn't have to be used for smart pointers. It can also be used for many other things, like locks, mutexes, temporary changes of cursors, etc. i.e. anything that is changed temporarily and restored at the end of a certain period. Just declare the RAII object inside the block and the change will be restored at the end of it. Just pass it an anonymous function to tell it what it must do at the end of the block (or in case of an exception).
But more about this later. FWIW, I also like the type inference, or that it can be used for for
-loops.
I think you meant I2.Talk instead of I.Talk and I3.Talk instead of I2.Talk.
ReplyDeleteUp to now those begin..end blocks without any if clause or anything normally did not change anything. So they could be removed without problems. Important to remember that this is not the case anymore starting with 10.3.
begin..end blocks without any if, else, while or for are probably very seldom, so I don't think it will make a big difference.
Delete