6

I have a class

type
  TLoadOption = class
  private
    FAutoSearch: Boolean;
  public
    property AutoSearch: Boolean read FAutoSearch write FAutoSearch;
  end;

In one of the functions i am creating the object of the class in stack

procedure MyView.InitializeForm(const aMsg: MyMsg);
//---------------------------------------------------------------------------
var
  Options: TLoadOption;
begin

  if aMsg.OptionalObject <> nil then
   Options := aMsg.OptionalObject as TLoadOption;

  if Assigned(Options) and Options.AutoSearch then
    DoRefresh;
end;

I am not passing anything in aMsg so ideally Options is not set.

In Delphi XE by default Options is set as nil and so this DoRefresh is not called but when i execute the same code in Delpi XE4 the options is initialized with some random value and AutoSearch becomes true always and it results in calling this DoRefresh function which is undesired.

I am wondering if there are any compiler options that set default values to uninitialized variable. My only solution as of now is like this

 procedure MyView.InitializeForm(const aMsg: MyMsg);
    //---------------------------------------------------------------------------
    var
      Options: TLoadOption;
    begin
      Options := nil;

      if aMsg.OptionalObject <> nil then
       Options := aMsg.OptionalObject as TLoadOption;

      if Assigned(Options) and Options.AutoSearch then
        DoRefresh;
    end;

is this a correct way?

3
  • 1
    What is MyMsg? This is a class, record or what? You say about default value, but this param have no default value in your case. How you assign default value? Commented Mar 7, 2014 at 10:26
  • 2
    Didn't the compiler warn you about that code? It should have told you that Options was uninitialized. Never ignore a compiler warning. Commented Mar 7, 2014 at 13:16
  • 1
    You accepted the answer that gave the best solution to your problem, but also did not actually answer the question you asked. You asked about initialization of a local variable. Commented Mar 10, 2014 at 7:04

5 Answers 5

11

A local class is not initialized. You need to set it to nil before testing its assignment.

See Are delphi variables initialized with a value by default?.

Only local reference-counted variables are initialized (example: String,dynamic arrays,interface,variants).

If you are targeting mobile platforms, where ARC (automatic reference counting) is introduced, classes are reference counted though. See Automatic Reference Counting in Delphi Mobile Compilers.

Sign up to request clarification or add additional context in comments.

Comments

7

As the other answers already said the local variable is not initialized. However what I like to add here is that as is nil safe. That means you don't need to check if aMsg.OptionalObject is assigned. You can just write:

var
  Options: TLoadOption;
begin
  Options := aMsg.OptionalObject as TLoadOption;

  if Assigned(Options) and Options.AutoSearch then
    DoRefresh;
end;

Keep in mind that it will throw an exception if OptionalObject does not inherit from TLoadOption. The code looks as that is always the case. So if you are sure about that you can use a hardcast:

begin
  if Assigned(aMsg.OptionalObject) and TLoadOption(aMsg.OptionalObject).AutoSearch then
    DoRefresh;
end;

Comments

6

No. Assuming that TLoadOption is an object (unmanaged reference type) you have to initialize local variables yourself. There is no option to have them initialized for you. Local variables for reference types (except for managed types like strings, etc) that are uninitialized will always contain whatever garbage data was in that location on the stack. This makes use of Assigned impossible.

You might just simplify your code a bit, but this is about as short as it can get.

var
  Options: TLoadOption;
begin
  if aMsg.OptionalObject <> nil then begin
    Options := aMsg.OptionalObject as TLoadOption;
    if Options.AutoSearch then DoRefresh;
  end;
end;

Comments

3

Options is a local variable, of a non-managed type. Which means that it is not initialized. It can have any value until you initialize it. If the variable sometimes happens to have the value nil without you having initialized it, then that's just unlucky for you.

You must initialize local variables before attempting to read them.

7 Comments

Thanks for your answer but i am curious on How it always work fine in XE?
@Jeeva He answered that - you were just lucky. The most likely explanation is that the calling function (or some previous function) semi-reliably left something higher up on the stack (where your variable ended up) that made the code work - and now that has somehow changed.
@Jeeva An uninitialized value can have any value. Including nil.
@Jeeva Are you sure you are building with the exact same options? It might already change if you change some compiler options (optimization, stack frames, etc).
@DavidHeffernan Fair point. Let us be neutral in making value judgements and perhaps say that it worked by chance... making what we will of that outcome ;D
|
1

You don't need local var at all.

procedure MyView.InitializeForm(const aMsg: MyMsg);
begin
  if Assigned(aMsg.OptionalObject)
    and (aMsg.OptionalObject is TLoadOption)
    and (aMsg.OptionalObject as TLoadOption).AutoSearch
  then
    DoRefresh;
end;

2 Comments

1. You don't need local var. 2. You don't need to initialize it. 3. If OptionalObject does not inherit from TLoadOption nothing will break. 4. As for me this code is logical.
The local var is good. It makes the code better. It allows you to avoid repeating yourself over and over as you do.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.