Jump to content
DelphiUdIT

Class not instantiated ... but method executed

Recommended Posts

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

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

 

  • Like 1

Share this post


Link to post
Posted (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 by Fr0sT.Brutal
  • Like 3
  • Thanks 1

Share this post


Link to post
Posted (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 by DelphiUdIT

Share this post


Link to post
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.

  • Thanks 1

Share this post


Link to post
Posted (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 by Dalija Prasnikar
  • Like 2

Share this post


Link to post

@Dalija

Thanks for your article. You have cleared up more than a few doubts.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×