4
votes

As it pertains to Delphi...

When a variable is declare of a certain type, is it initialized to an OBJECT of that type? Or must the variable be assigned an expression which returns an object of that type?

I'm coming from a strong Java background. What I mean to ask is this... In Java, say you declare an instance variable of a user defined type named Orange. Which would look like this:

private Orange _fruit;

The variable _fruit still holds a reference to null until actually assigned an instance of the Orange class, like this:

_fruit = new Orange();

In Delphi if I declare a variable of type TForm, like this:

var
  Form : TForm;

Is Form initlized to a TForm object? Or is it still nil?

I'm asking because I'm getting an error when trying to compile a small bit of code which is showen below:

Here is the Main unit:

unit Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils,
  System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Second;

type
  TForm1 = class(TForm)
    ShowForm2: TButton;
    procedure ShowForm2Click(Sender: TObject);
  end;

var
  Form1: TForm1;
  SecondForm : TSecondForm;

implementation

{$R *.dfm}

procedure TForm1.ShowForm2Click(Sender: TObject);
begin
SecondForm.ShowModal;
end;
end.

and here is the Second unit:

unit Second;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Vcl.StdCtrls;

type
  TSecondForm = class(TForm)
    Label1: TLabel;
  end;

var
  SecondForm: TSecondForm;

implementation

{$R *.dfm}

end.

The error I'm getting when I try to compile is exactly: "Access violation at address 005B17F9 in module 'Multiple.exe'. Read of address 00000000." I was thinking that it's because I don't somehow initialize the variable SecondForm in unit Main? However, I tried to place 'SecondForm.Create' in the ShowForm2Click procedure and I get the same error. Am I get this error because SecondForm is unassigned? Does it need to be initialized? Or is it?

Note: I'm three days new to Delphi. Please be considerate of that.

3

3 Answers

3
votes

also note that unit Second and unit Main both declare a global variable

SecondForm : TSecondForm; 

In the case of the main unit your main unit will be hiding the SecondForm variable declared in unit Second (even though it lists it in the uses clause). In the case of a Delphi VCL Forms application, if the SecondForm is an auto-create form then the SecondForm declared in unit Second will not be nil and will in fact already have an instance of TSecondForm created and assigned to it, but this will be inaccessible by unit Main because it declares a global of the same name (which, like all reference types, will be nil until you do something with it).

In short, it's probably best not to declare a global SecondForm : TSecondForm in unit Main - call it something else or else use the global declared in unit Second. If SecondForm is an auto-create form (default behaviour) then the above code would work if you simply did not re-declare SecondForm in unit Main - if not you would still have to instantiate SecondForm.

VCL Forms are automatically auto-create forms unless you otherwise specify. Check menu:

 Project > Options > Forms

to see or change which forms will automatically have an instance assigned to their IDE-generated globals.

5
votes

SecondForm.Create is the wrong syntax. Constructors are special in Delphi. You can think of them more or less like class methods. The way you invoke them is like this:

variable := ClassType.Create(arguments);

While it is possible to invoke a constructor like an instance method (variable.Create) this is for one specific use case and should not be done in general code. The reason to call a constructor on an object and not a type is if you're already inside a constructor for that object. (ie. if you have more than one constructor on the object and one of them calls another one, or to initialize the ancestor class's members by calling a constructor on the parent class with inherited Create(arguments);)

What you did, calling a constructor on an object when not inside another constructor for that object, should probably raise a compiler warning, if not an error, but unfortunately it doesn't.

3
votes

Yes, SecondForm is nil until you assign it.

Try something like this:

procedure TForm1.ShowForm2Click(Sender: TObject);
begin
  with TSecondForm.Create(nil) do try
     ShowModal;
  finally
     Free;
  end;
end;