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?
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
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.
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.
Just as a side note (as you are new to Delphi): Global variables can be initialized directly when declaring them:
var myGlobal:integer=99;
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.
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.
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.
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."
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??
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;
Related
I read many posts on forum about pointers, Assigned function, Free function, FreeAndNil function, etc... I already know Free function don't remove the pointer reference to an object assigned and FreeAndNil does it... All posts I read treat this subject considering Create method already was executed, or in other words, considering an object already created.
My question is: Why Assigned function returns true for a uninitialized object variable ?
Follow an example:
procedure TForm1.FormCreate(Sender: TObject);
var
Qry: TADOQuery;
begin
if Assigned(Qry) then
ShowMessage('Assigned')
else
ShowMessage('Unassigned');
Qry := TADOQuery.Create(nil);
if Assigned(Qry) then
ShowMessage('Assigned')
else
ShowMessage('Unassigned');
end;
That example displays 'Assigned' twice!
Conclusion: Immediately after Qry has been declared and before its create method has been executed the pointer to Qry isn't NIL !
If I put Qry := nil; at the first line into procedure above everything works fine... it displays 'Unassigned' and 'Assigned'.
Why??
Is there any safe way to know if a class variable already has its create method executed?
Your variable is a local variable and so is not initialized. It could contain any value.
The documentation says:
On the Win32 platform, the contents of
a local variable are undefined until a value is assigned to
them.
Note that, as an implementation detail, some types are managed and even local variables of managed types are initialized. Examples of managed types include: strings, interfaces, dynamic arrays, anonymous types and variants.
You ask:
Is there any safe way to know if a class variable already has its create method executed?
If that variable is a local variable, the answer is no. The onus falls to you the programmer. In practice it is seldom an issue because good code has short procedures which makes it harder for you to slip up. And even if you do the compiler will invariably warn you.
Other types of variables like class fields and global variables are initialized.
Because when creating a pointer, it cames with whatever garbage value was in that memory position. If you want to write NIL in it, it takes some CPU cycles, and I think it's not automatically done by Delphi because you may want something faster. In your example, why assign NIL to a variable, if soon afterwards you're going to put another value in it?
From the documentation of the Assigned function (emphasis mine):
Use Assigned to determine whether the pointer or procedure referenced by P is nil. P must be a variable reference of a pointer or procedural type. Assigned(P) corresponds to the test P<> nil for a pointer variable, and #P <> nil for a procedural variable.
Assigned returns false if P is nil, true otherwise.
Note: Assigned can't detect a dangling pointer--that is, one that isn't nil but no longer points to valid data. For example, in the code example for Assigned, Assigned won't detect the fact that P isn't valid.
The Assigned function is effectively implemented as:
function Assigned(const P): Boolean;
begin
Result := Pointer(P) <> nil;
end;
So the function isn't really checking whether the value truly is assigned. Rather it's checking a side-effect of being assigned.
As a result the function is guaranteed to return True if it is assigned.
But behaviour is undefined if the value is uninitialised. Basically since an uninitialised value has a garbage value left over from previous operations, it might be nil, or if might not.
Another thing to note is that Assigned has no way to determine the validity of its value. E.g. The following call to Assigned returns True even though the underlying object is no longer valid.
var
LObject: TObject;
begin
LObject := TObject.Create;
LObject.Free;
if Assigned(LObject) then ShowMessage('Still assigned!?');
end;
EDIT: Addendum
In response to the second part of your question.
Is there any safe way to know if a class variable already has its create method executed?
There is no safe way to determine if an object instance has been created. (There's also no way to reliably confirm that it hasn't already been destroyed.)
However, there are conventions (and good practices) you can follow to help you on the way.
First note that you should only be "unsure" if something was created if it's a deliberate feature of that piece of code. E.g. If you intend an object to be "lazy initialised".
What I'm trying to say here is: Never check Assigned just because you're worried that there might be a bug that prevents it from being assigned.
Not only is this impossible to do reliably, but you overcomplicate your code... Which increases the chance of bugs.
Also if you find something is unexpectedly not Assigned, then what can you do about it? Ignoring it would simply be pointless. Also, it's no good saying: "Ok, then I'll create the object". Because then you're duplicating creation logic in multiple places.
Basically you should try to make every part of your program correct - not have your program try to double-check itself everywhere.
So now that we're (hopefully) agreed that you only check if something is created if you've deliberately chosen that being created is optional. You do this as follows:
At first opportunity, ensure the variable/field reference is initialised to nil. So then it's guranteed to be assigned a value which means the object is not created. (Yes, the naming is a bit warped.)
You can set the vairable/field reference to a new instance of an object or set it by copying another reference of an already existing object. (Note the existing refernce might also be nil, but that doesn't cause any problems.)
If you ever destroy the object (or even just want to stop using it from that reference), set your variable/field reference to nil again.
NOTE: Delphi already initialises the member fields of a new class. So those won't need special attention.
Instead of me being able to just type
const clicks : Integer = 1;
I have to type
{$J+}
const clicks : Integer = 1;
{$J-}
I think its alot easier to just checked the box in the compiler options menu.. but i wanted to make sure that it wouldnt hurt me in the long wrong.. and was wondering why it would be disabled (Un-checked)?
I appreciate any help on this, thank you guys.
The default has been to disable them since Delphi 2 was released, IIRC. The actual option was provided in the dialog with Delphi 1, and I seem to recall a fuss about the default having changed from enabled to disabled in the next version. It's been a long time though, so I could be off by one on when the default was reversed; it may have been D3. Assignable constants are a carry-over from the old Turbo Pascal days, and are a substitute for the lack of an actual static variable type. They were replaced by a better solution, which is initialized (global) variables (see Declaring Variables).
If you have an actual need to use a writable constant, you should do so only on the smallest (most limited) scope where it's necessary, rather than changing the global setting. Constants should be exactly that where possible (constant). The typical reason for using writable constants is when you require a local variable within a certain scope (such as a procedure, function, or unit) that needs to keep its value between calls, and there is usually a better way to do so. Some of the options are object fields (member variables), or limited scope initialized variables (variables visible in restricted areas, such as within the implementation section of a unit, and initialized to a starting value).
Assignable constants means the value can be changed at runtime, and is really rarely useful. True constants are just that - constant - and shouldn't be allowed to change.
The same can be said for typed constants; there should be an actual need for using them, and there rarely is unless you're storing a constant array, record, pointer, or procedural type, as in these declarations:
const
TIntLookupArray: array[0..1] of Integer = (1, 2);
TErrorMsgs: array[0..1] of string = ('Invalid input', 'Invalid sequence');
Is there a reason you're using typed constants in the first place? You won't have this problem if you just use
const clicks = 1;
and let the compiler decide the proper type. If you want to make sure it's the size of an Integer, just use a typecast like
const clicks = Integer(1);
See the Delphi documentation docwiki for more info.
I guess it has been disabled because "assignable constants" is a contadiction in itself. You can probably replace your code by
var
clicks : Integer = 1;
The only situation where "assignable constants" are slightly useful is to simulate a static local C variable.
The assignable typed constants option has been disabled by default for as long as I can remember. It was disabled by default in many versions preceeding Delphi 7.
The language feature is poorly designed and because of that, in my view, should not be used. It is confusing to readers of the code. The idea of modifying a constant is quite simply bizarre. The use-case for assignable typed constants is locally scoped variables with static (i.e. global) storage duration.
If the language had been properly designed then there would be a place for locally scoped variables with static storage duration. But the design was fatally flawed because you cannot, in the Delphi language, readily distinguish between assignable typed constants and real constants, due to the overloading of the const keyword.
A sane design would have introduced syntax to declare variables with static storage and distinguish them from constants. But instead the designers chose a compiler option. Or perhaps, way back when, in Turbo Pascal all typed constants were assignable. All the same, without language syntax support, the overloading of the const keyword is simply untenable.
The compiler option is retained for backwards compatibility. You are not expected to use assignable typed constants. Again, for as long as I can remember, any decent coding standard bans the use of assignable typed constants.
My recommendations:
Disable assignable typed constants at the global level.
Never use $J+ in your code.
The closest construct in modern Delphi for locally scoped variables with static storage duration is strict private class variables. They are not available in Delphi 7 and so your only option is a global variable, which is a rather sorry state of affairs.
Let's say you have a local record that you'd like to initialize:
type
TMyRec=record
Val1, Val2:Integer;
end;
procedure MyProc;
var
MyVar:TMyRec;
begin
// ... ?
WriteLn(Val1,Val2);
end;
Besides setting each field "manually", there are several ways to do it.
Use Initialize():
Initialize(MyVar);
Use Default():
MyVar := Default(TMyVar);
Use FillChar:
FillChar(MyVar,SizeOf(MyVar),0);
Define an empty constant, and assign that to the var
const cMyVar:TMyVar=();
...
MyVar := cMyVar;
The above all seem to work in situations like this example. I guess you could even define a global variable to get it initialized.
But is there a preferred method? Or are there certain situations where it's not recommended to use any of the above, or where it simply won't work?
To put it short, what's the definitive Right Waytm to initialize a local stack variable? :-)
Never use Initialize for local variables.
Initialize should be used only in Delphi code where a variable is dynamically allocated by other means than the New standard procedure.
What's more it would be optimized to a nop with your record since it doesn't contain any managed types. So, we can throw this option away and reduce the field to three contenders.
The remaining three contenders all have the same effect for an uninitialized local variable. However, it's risky to use FillChar on a local variable with managed members, e.g. strings, interface references, variants etc. If the managed members have been initialized then you will break the reference counting mechanism. However, if you are sure that the record has not been initialized, then FillChar is safe and efficient, albeit rather ugly looking in my view. Personally, I would reject FillChar for this role.
That leaves Default(T) and the constant assignment. In older versions of Delphi you can only use the constant assignment. It's fair to say that the constant assignment is as ugly as FillChar, by the time you've declared the constant. So, in modern Delphi versions I would opt for Default() since it is more concise and reads better, in my view.
As was discussed in a question covering similar ground, the compiler produces very efficient code when you assign Default(T) to a variable.
I know that, in Delphi, instance variables and global variables are initialized to zero (this has been asked here before).
However, what about static variables (class var)? I would expect class vars to be initialized to zero, just like global variables. But I've seen too many new Delphi compiler features that were still half-baked to assume that it works, without documentation that actually states a guarantee.
The Help has no index entry for "class var". The "Fields" topic mentions class fields, but does not specify whether they're initialized at program startup. And the obvious fix, of explicitly initializing them (class var X: Integer = 0;), doesn't compile ("';' expected but '=' found").
Are class variables initialized to zero? Is there documentation that explicitly states this?
I'm not aware of any documentation that explicitly states it, but class vars are just a special type of global variable, and globals get zeroed.
One nice thing about anonymous methods is that I can use variables that are local in the calling context. Is there any reason why this does not work for out-parameters and function results?
function ReturnTwoStrings (out Str1 : String) : String;
begin
ExecuteProcedure (procedure
begin
Str1 := 'First String';
Result := 'Second String';
end);
end;
Very artificial example of course, but I ran into some situations where this would have been useful.
When I try to compile this, the compiler complains that he "cannot capture symbols". Also, I got an internal error once when I tried to do this.
EDIT I just realized that it works for normal parameters like
... (List : TList)
Isn't that as problematic as the other cases? Who guarantees that the reference is still pointing to an alive object whenever the anonymous method is executed?
Var and out parameters and the Result variable cannot be captured because the safety of this operation cannot be statically verified. When the Result variable is of a managed type, such as a string or an interface, the storage is actually allocated by the caller and a reference to this storage is passed as an implicit parameter; in other words, the Result variable, depending on its type, is just like an out parameter.
The safety cannot be verified for the reason Jon mentioned. The closure created by an anonymous method can outlive the method activation where it was created, and can similarly outlive the activation of the method that called the method where it was created. Thus, any var or out parameters or Result variables captured could end up orphaned, and any writes to them from inside the closure in the future would corrupt the stack.
Of course, Delphi does not run in a managed environment, and it doesn't have the same safety restrictions as e.g. C#. The language could let you do what you want. However, it would result in hard to diagnose bugs in situations where it went wrong. The bad behaviour would manifest itself as local variables in a routine changing value with no visible proximate cause; it would be even worse if the method reference were called from another thread.
This would be fairly hard to debug. Even hardware memory breakpoints would be a relatively poor tool, as the stack is modified frequently. One would need to turn on the hardware memory breakpoints conditionally upon hitting another breakpoint (e.g. upon method entry). The Delphi debugger can do this, but I would hazard a guess that most people don't know about the technique.
Update: With respect to the additions to your question, the semantics of passing instance references by value is little different between methods that contain a closure (and capture the paramete0 and methods that don't contain a closure. Either method may retain a reference to the argument passed by value; methods not capturing the parameter may simply add the reference to a list, or store it in a private field.
The situation is different with parameters passed by reference because the expectations of the caller are different. A programmer doing this:
procedure GetSomeString(out s: string);
// ...
GetSomeString(s);
would be extremely surprised if GetSomeString were to keep a reference to the s variable passed in. On the other hand:
procedure AddObject(obj: TObject);
// ...
AddObject(TObject.Create);
It is not surprising that AddObject keeps a reference, since the very name implies that it's adding the parameter to some stateful store. Whether that stateful store is in the form of a closure or not is an implementation detail of the AddObject method.
The problem is that your Str1 variable is not "owned" by ReturnTwoStrings, so that your anonymous method cannot capture it.
The reason it cannot capture it, is that the compiler does not know the ultimate owner (somewhere in the call stack towards calling ReturnTwoStrings) so it cannot determine where to capture it from.
Edit: (Added after a comment of Smasher)
The core of anonymous methods is that they capture the variables (not their values).
Allen Bauer (CodeGear) explains a bit more about variable capturing in his blog.
There is a C# question about circumventing your problem as well.
The out parameter and return value are irrelevant after the function returns - how would you expect the anonymous method to behave if you captured it and executed it later? (In particular, if you use the anonymous method to create a delegate but never execute it, the out parameter and return value wouldn't be set by the time the function returned.)
Out parameters are particularly difficult - the variable that the out parameter aliases may not even exist by the time you later call the delegate. For example, suppose you were able to capture the out parameter and return the anonymous method, but the out parameter is a local variable in the calling function, and it's on the stack. If the calling method then returned after storing the delegate somewhere (or returning it) what would happen when the delegate was finally called? Where would it write to when the out parameter's value was set?
I'm putting this in a separate answer because your EDIT makes your question really different.
I'll probably extend this answer later as I'm in a bit of a hurry to get to a client.
Your edit indicates you need to rethink about value types, reference types and the effect of var, out, const and no parameter marking at all.
Let's do the value types thing first.
The values of value types live on the stack and have a copy-on-assignment behaviour.
(I'll try to include an example on that later).
When you have no parameter marking, the actual value passed to a method (procedure or function) will be copied to the local value of that parameter inside the method. So the method does not operate on the value passed to it, but on a copy.
When you have out, var or const, then no copy takes place: the method will refer to the actual value passed. For var, it will allow to to change that actual value, for const it will not allow that. For out, you won't be able to read the actual value, but still be able to write the actual value.
Values of reference types live on the heap, so for them it hardly matters if you have out, var, const or no parameter marking: when you change something, you change the value on the heap.
For reference types, you still get a copy when you have no parameter marking, but that is a copy of a reference that still points to the value on the heap.
This is where anonymous methods get complicated: they do a variable capture.
(Barry can probably explain this even better, but I'll give it a try)
In your edited case, the anonymous method will capture the local copy of the List. The anonymous method will work on that local copy, and from a compiler perspective everything is dandy.
However, the crux of your edit is the combination of 'it works for normal parameters' and 'who guarantees that the reference is still pointing to an alive object whenever the anonymous method is executed'.
That is always a problem with reference parameters, no matter if you use anonymous methods or not.
For instance this:
procedure TMyClass.AddObject(Value: TObject);
begin
FValue := Value;
end;
procedure TMyClass.DoSomething();
begin
ShowMessage(FValue.ToString());
end;
Who guarantees that when someone calls DoSomething, that the instance where FValue points to still exists?
The answer is that you must guarantee this yourself by not calling DoSomething when the instance to FValue has died.
The same holds for your edit: you should not call the anonymous method when the underlying instance has died.
This is one of the areas where reference counted or garbage collected solutions make life easier: there the instance will be kept alive until the last reference to it has gone away (which might cause instance to live longer than you originally anticipated!).
So, with your edit, your question actually changes from anonymous methods to the implications of using reference typed parameters and lifetime management in general.
Hopefully my answer helps you going in that area.
--jeroen