115

I'm new to Delphi, and I've been running some tests to see what object variables and stack variables are initialized to by default:

TInstanceVariables = class
  fBoolean: boolean; // always starts off as false
  fInteger: integer; // always starts off as zero
  fObject: TObject; // always starts off as nil
end;

This is the behaviour I'm used to from other languages, but I'm wondering if it's safe to rely on it in Delphi? For example, I'm wondering if it might depend on a compiler setting, or perhaps work differently on different machines. Is it normal to rely on default initialized values for objects, or do you explicitly set all instance variables in the constructor?

As for stack (procedure-level) variables, my tests are showing that unitialized booleans are true, unitialized integers are 2129993264, and uninialized objects are just invalid pointers (i.e. not nil). I'm guessing the norm is to always set procedure-level variables before accessing them?

dan-gph
  • 16,301
  • 12
  • 61
  • 79
MB.
  • 7,365
  • 6
  • 42
  • 42
  • 4
    Two notes: 1. Records are not initialized. 2. Reference counted variables are always initialized. !BUT! in a function that returns a string, 'Result' is not initialized to empty string as you may expect. This is because 'Result' is not a local var. So, always do: Result:= ''; – Gabriel Jan 27 '17 at 10:39
  • also see: [Which variables are initialized when in Delphi?](http://stackoverflow.com/questions/861045/which-variables-are-initialized-when-in-delphi) – Gabriel Jan 27 '17 at 10:47

10 Answers10

118

Yes, this is the documented behaviour:

  • Object fields are always initialized to 0, 0.0, '', False, nil or whatever applies.

  • Global variables are always initialized to 0 etc as well;

  • Local reference-counted* variables are always initialized to nil or '';

  • Local non reference-counted* variables are uninitialized so you have to assign a value before you can use them.

I remember that Barry Kelly somewhere wrote a definition for "reference-counted", but cannot find it any more, so this should do in the meantime:

reference-counted == that are reference-counted themselves, or directly or indirectly contain fields (for records) or elements (for arrays) that are reference-counted like: string, variant, interface or dynamic array or static array containing such types.

Notes:

  • record itself is not enough to become reference-counted
  • I have not tried this with generics yet
Community
  • 1
  • 1
Giacomo Degli Esposti
  • 2,392
  • 1
  • 15
  • 20
  • 2
    As Giacomo pointed out in the comments below, this is all explained in the Delphi help files at ms-help://borland.bds4/bds4ref/html/Variables.htm. In Delphi 2009 I found the same info by searching the help for "variables" (funnily enough I tried lots of searches but I didn't think to try that one). – MB. Sep 25 '08 at 14:06
  • 9
    Local variables ARE initialized ($0) if they are of a managed type like strings, interfaces, dynamic arrays or variants – Francesca Sep 25 '08 at 16:58
  • 2
    If this is 'the' answer, I think someone should add what sets and enums are initialized to for completeness. – Peter Turner Nov 14 '08 at 19:30
  • 5
    There's an exception, though! When you override the constructor, and don't call the inherited constructor, there's a chance that some fields end up uninitialized! (Especially with older Delphi versions.) Since TObject.Create is responsible for zeroing all data, not calling that one results in possible unknown data. – Wim ten Brink Nov 02 '10 at 19:54
  • @François your comment saved my day. Was having problems with unitialized records and changing the fields to variants solved it. – Fabio Gomes May 29 '12 at 14:44
  • 20
    @WimtenBrink I think you are wrong. Initialization is not done within `TObject.Create`, which is a void method, but in `class function TObject.InitInstance(Instance: Pointer): TObject;` which is ALWAYS called before any constructor call, even for older Delphi versions. Your comment is IMHO wrong and confusing. – Arnaud Bouchez Aug 31 '12 at 15:52
  • 9
    Don't forget that in a function that returns a string, 'Result' is not initialized to empty string as you may expect. This is because 'Result' is not a local var. – Gabriel Feb 06 '15 at 21:49
  • 1
    This is the current link, that documents the initializations: http://docwiki.embarcadero.com/RADStudio/Berlin/en/Variables – yonojoy Nov 10 '16 at 09:55
29

Global variables that don't have an explicit initializer are allocated in the BSS section in the executable. They don't actually take up any space in the EXE; the BSS section is a special section that the OS allocates and clears to zero. On other operating systems, there are similar mechanisms.

You can depend on global variables being zero-initialized.

Barry Kelly
  • 41,404
  • 5
  • 117
  • 189
26

Class fields are default zero. This is documented so you can rely on it. Local stack varaiables are undefined unless string or interface, these are set to zero.

Martin Liesén
  • 1,308
  • 11
  • 14
  • Thanks. "Zero" is confusing me a bit - does that mean strings are '', and interfaces are nil? – MB. Sep 25 '08 at 11:35
  • 4
    Yes, exactly that. nil = 0 (at the assembler level) and '' = nil (Delphi convention). – gabr Sep 25 '08 at 11:40
  • 4
    "unless string or interface" is not a complete description of reality. Dynamic arrays, for instance, are also initialized. More generally, the rule is that variables of managed (reference-counted) types are initialized, even if local. – Andreas Rejbrand Sep 04 '19 at 08:42
  • 1
    ...and don't confuse *local stack variables* with `Result`, see https://stackoverflow.com/q/5336863/2932052 – Wolf Sep 06 '21 at 10:15
19

Just as a side note (as you are new to Delphi): Global variables can be initialized directly when declaring them:

var myGlobal:integer=99;
bluish
  • 26,356
  • 27
  • 122
  • 180
Heinrich Ulbricht
  • 10,064
  • 4
  • 54
  • 85
9

Global variables and object instance data (fields) are always initialized to zero. Local variables in procedures and methods are not initialized in Win32 Delphi; their content is undefined until you assign them a value in code.

Ondrej Kelle
  • 36,941
  • 2
  • 65
  • 128
9

Here's a quote from Ray Lischners Delphi in a Nutshell Chapter 2

"When Delphi first creates an object, all of the fields start out empty, that is, pointers are initialized to nil, strings and dynamic arrays are empty, numbers have the value zero, Boolean fields are False, and Variants are set to Unassigned. (See NewInstance and InitInstance in Chapter 5 for details.)"

It's true that local-in-scope variables need to be initialised... I'd treat the comment above that "Global variables are initialised" as dubious until provided with a reference - I don't believe that.

edit... Barry Kelly says you can depend on them being zero-initialised, and since he's on the Delphi compiler team I believe that stands :) Thanks Barry.

Drew Gibson
  • 1,624
  • 3
  • 18
  • 22
  • 3
    In delphi 2006 help you can find it here: ms-help://borland.bds4/bds4ref/html/Variables.htm "If you don't explicitly initialize a global variable, the compiler initializes it to 0. Object instance data (fields) are also initialized to 0. " – Giacomo Degli Esposti Sep 25 '08 at 13:59
  • 2
    Downvoted because of "I don't believe that". This is programming, not religion. And Giacomo just demonstrated the truth. – Gabriel Jan 06 '20 at 13:02
8

Even if a language does offer default initializations, I don't believe you should rely on them. Initializing to a value makes it much more clear to other developers who might not know about default initializations in the language and prevents problems across compilers.

Thomas Owens
  • 114,398
  • 98
  • 311
  • 431
  • 6
    Of course you can. And you should. Initializing everything to 0/''/false/nil in every constructor is just unnecessary. Initializing global variables, on other hand, is not so stupid - I for once can never remember if they are initialized or not (as I'm not using them much). – gabr Sep 25 '08 at 12:03
  • 4
    If Delphi let you initialize a variable at the same point as you declare it (e.g. var fObject: TObject = nil) I'd be inclined to agree that initializing to a value is probably a good idea. But to me it seems a bit much to do it in the constructor for every object field. – MB. Sep 25 '08 at 12:15
6

From Delphi 2007 help file:

ms-help://borland.bds5/devcommon/variables_xml.html

"If you don't explicitly initialize a global variable, the compiler initializes it to 0."

Ondrej Kelle
  • 36,941
  • 2
  • 65
  • 128
6

I have one little gripe with the answers given. Delphi zeros out the memory space of the globals and the newly-created objects. While this NORMALLY means they are initialized there is one case where they aren't: enumerated types with specific values. What if zero isn't a legal value??

Loren Pechtel
  • 8,945
  • 3
  • 33
  • 45
  • 1
    Zero is always a legal values, it is the 1st value of the enum. you can see it with ord(MyFirstEnumValue). – Francesca Sep 25 '08 at 16:48
  • It would return the first value in the enumerated type. – skamradt Sep 25 '08 at 16:49
  • 8
    Zero is not always a legal value if you explicitly assign values to the enum. In that case, it's still initialized to 0, and you have an illegal value. But enums are just syntactic sugar painted over normal integer types, so this doesn't really break anything. Make sure your code can deal with it. – Mason Wheeler Feb 12 '09 at 17:04
  • 2
    @François: Not if you define your enum like this: `TOneTwoThree = (One=1, Two=2, Three=3);` – fnkr Feb 10 '16 at 09:22
2

Newly introduced (since Delphi 10.3) inline variables are making the control of initial values easier.

procedure TestInlineVariable;
begin
  var index: Integer := 345;
  ShowMessage(index.ToString);
end;
Jacek Krawczyk
  • 2,083
  • 1
  • 19
  • 25