DelphiUdIT 176 Posted April 4, 2022 Look at this code and run it (VCL Applicaton with a Form, a Button with OnClick Event and a custom class) unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type TDoSomething = class Danger: string; constructor create; function Ghost: boolean; end; type { TForm1 } TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private public end; var Form1: TForm1; DoSomething: TDoSomething; implementation {$R *.dfm} constructor TDoSomething.create; begin //FROM HERE I NEVER GO THERE .... AND IF I GO THERE BY WRONG, CLOSE THE PROGRAM !!! ExitProcess(0); end; function TDoSomething.Ghost: boolean; begin try result := true; ShowMessage('Here I am, I am a ghost'); except result := false; end; end; procedure TForm1.Button1Click(Sender: TObject); begin if DoSomething.Ghost then //<------- DoSomething is NIL !! ShowMessage('OK, executed') else ShowMessage('KO, some errors append'); end; end. The class is not instantiated, but the GHOST function is executed. Am I missing something? I trust in my abysmal ignorance, because otherwise much more than a certainty collapses ... In tens of years of programming I have never dared to write anything like this, taking some concepts for granted. Aside from the fact that the program doesn't make much sense (good programming rules would also like a "if Assigned(DoSomething) then" before using it), such code cannot run ... at runtime I would expect an error. Hope someone can explain this. Bye Share this post Link to post
Lajos Juhász 293 Posted April 4, 2022 Languages that use manual memory management requires from the developers to take care about pointers. You have manually to initialize and also to free them. A bit more interesting result is with local variable: program Project1; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; type TDoSomething = class Danger: string; constructor create; function Ghost: boolean; end; var DoSomething2: TDoSomething; procedure MainProc; var DoSomething: TDoSomething; begin WriteLn('DoSomething = ',NativeInt(DoSomething)); if Assigned(DoSomething) then WriteLn('DoSomething is not nil'); WriteLn('DoSomething2 = ',NativeInt(DoSomething2)); DoSomething.Ghost; end; { TDoSomething } constructor TDoSomething.create; begin //FROM HERE I NEVER GO THERE .... AND IF I GO THERE BY WRONG, CLOSE THE PROGRAM !!! writeLn('TDoSomething.create'); end; function TDoSomething.Ghost: boolean; begin try result := true; WriteLn('Here I am, I am a ghost'); except result := false; end; end; begin try { TODO -oUser -cConsole Main : Insert code here } MainProc; ReadLn; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end. DoSomething = 4318856 DoSomething is not nil DoSomething2 = 0 Here I am, I am a ghost 1 Share this post Link to post
Fr0sT.Brutal 900 Posted April 4, 2022 (edited) Methods are just routines with implicit 1st argument set to Self. If you're not using Self inside them, they will work. Try to add some internal string field and show it inside Ghost, then you'll get what you expect Edited April 4, 2022 by Fr0sT.Brutal 3 1 Share this post Link to post
DelphiUdIT 176 Posted April 4, 2022 (edited) This is new to me ... a non-instantiated object that "executes" a method .... 4 hours ago, Fr0sT.Brutal said: Try to add some internal string field and show it inside Ghost, then you'll get what you expect Yes, of course an exception is thrown: it must be like this because a string needs to have memory allocated. Anyway, thanks for the explanation. I thought that without an "instance" a method could not be executed, or rather that an exception was thrown. You never stop learning. <---- I mean I never stop learning (EDIT) Bye Edited April 4, 2022 by DelphiUdIT Share this post Link to post
Stefan Glienke 2002 Posted April 4, 2022 1 hour ago, DelphiUdIT said: could not be executed, or rather that an exception was thrown. You never stop learning. Delphi does not do caller site checks such as Java or .NET do. 1 Share this post Link to post
Dalija Prasnikar 1396 Posted April 4, 2022 (edited) 1 hour ago, DelphiUdIT said: This is new to me ... a non-instantiated object that "executes" a method .... Executing method on nil reference is actually a language feature. But such method must be static and you must not access any instance fields if instance is nil. One such method is TObject.Free that can be safely called on nil reference, because it checks whether object is nil before calling other code, in this case virtual destructor that cannot be executed on nil instance. procedure TObject.Free; begin if Self <> nil then Destroy; end; Additional explanation how static method dispatching works can be found here https://dalijap.blogspot.com/2021/07/virtual-methods-in-delphi.html Edited April 4, 2022 by Dalija Prasnikar 2 Share this post Link to post
DelphiUdIT 176 Posted April 4, 2022 @Dalija Thanks for your article. You have cleared up more than a few doubts. Share this post Link to post