Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6118071
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 23, 20262026-05-23T15:23:36+00:00 2026-05-23T15:23:36+00:00

Gradually I’ve been using more variants – they can be very useful in certain

  • 0

Gradually I’ve been using more variants – they can be very useful in certain places for carrying data types that are not known at compile time. One useful value is UnAssigned (‘I’ve not got a value for you’). I think I discovered a long time ago that the function:

function DoSomething : variant;
begin
  If SomeBoolean then
    Result := 4.5
end;

appeared to be equivalent to:

function DoSomething : variant;
begin 
  If SomeBoolean then
    Result := 4.5
   else
   Result := Unassigned; // <<<<
end;

I presumed this reasoning that a variant has to be created dynamically and if SomeBoolean was FALSE, the compiler had created it but it was ‘Unassigned’ (<> nil?). To further encourage this thinking, the compiler reports no warning if you omit assigning Result.

Just now I’ve spotted nasty bug where my first example (where ‘Result’ is not explicity defaulted to ‘nil’) actually returned an ‘old’ value from somewhere else.

Should I ALWAYS assign Result (as I do when using prefefined types) when returing a variant?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-23T15:23:37+00:00Added an answer on May 23, 2026 at 3:23 pm

    Yes, you always need to initialize the Result of a function, even if it’s a managed type (like string and Variant). The compiler does generate some code to initialize the future return value of a Variant function for you (at least the Delphi 2010 compiler I used for testing purposes does) but the compiler doesn’t guarantee your Result is initialized; This only makes testing more difficult, because you might run into a case where your Result was initialized, base your decisions on that, only to later discover your code is buggy because under certain circumstances the Result wasn’t initialized.

    From my investigation, I’ve noticed:

    • If your result is assigned to a global variable, your function is called with an initialized hidden temporary variable, creating the illusion that the Result is magically initialized.
    • If you make two assignments to the same global variable, you’ll get two distinct hidden temporary variables, re-enforcing the illusion that Result’s are initialized.
    • If you make two assignments to the same global variable but don’t use the global variable between calls, the compiler only uses 1 hidden temporary, braking the previous rule!
    • If your variable is local to the calling procedure, no intermediary hidden local variable is used at all, so the Result isn’t initialized.

    Demonstration:

    First, here’s the proof that a function returning a Variant receives a var Result:
    Variant
    hidden parameter. The following two compile to the exact same assembler, shown below:

    procedure RetVarProc(var V:Variant);
    begin
      V := 1;
    end;
    
    function RetVarFunc: Variant;
    begin
      Result := 1;
    end;
    
    // Generated assembler:
    push ebx // needs to be saved
    mov ebx, eax // EAX contains the address of the return Variant, copies that to EBX
    mov eax, ebx // ... not a very smart compiler
    mov edx, $00000001
    mov cl, $01
    call @VarFromInt
    pop ebx
    ret
    

    Next, it’s interesting to see how the call for the two is set up by the complier. Here’s what happens for a call to a procedure that has a var X:Variant parameter:

    procedure Test;
    var X: Variant;
    begin
      ProcThatTakesOneVarParameter(X);
    end;
    
    // compiles to:
    lea eax, [ebp - $10]; // EAX gets the address of the local variable X
    call ProcThatTakesOneVarParameter
    

    If we make that “X” a global variable, and we call the function returning a Variant, we get this code:

    var X: Variant;
    
    procedure Test;
    begin
      X := FuncReturningVar;
    end;
    
    // compiles to:
    lea eax, [ebp-$10] // EAX gets the address of a HIDDEN local variable.
    call FuncReturningVar // Calls our function with the local variable as parameter
    lea edx, [ebp-$10] // EDX gets the address of the same HIDDEN local variable.
    mov eax, $00123445 // EAX is loaded with the address of the global variable X
    call @VarCopy // This moves the result of FuncReturningVar into the global variable X
    

    If you look at the prologue of this function you’ll notice the local variable that’s used as a temporary parameter for the call to FuncReturningVar is initialized to ZERO. If the function doesn’t contain any Result := statements, X would be “Uninitialized”. If we call the function again, a DIFFERENT temporary and hidden variable is used! Here’s a bit of sample code to see that:

    var X: Variant; // global variable
    procedure Test;
    begin
      X := FuncReturningVar;
      WriteLn(X); // Make sure we use "X"
      X := FuncReturningVar;
      WriteLn(X); // Again, make sure we use "X"
    end;
    
    // compiles to:
    lea eax, [ebp-$10] // first local temporary
    call FuncReturningVar
    lea edx, [ebp-$10]
    mov eax, $00123456
    call @VarCopy
    // [call to WriteLn using the actual address of X removed]
    lea eax, [ebp-$20] // a DIFFERENT local temporary, again, initialized to Unassigned
    call FuncReturningVar
    // [ same as before, removed for brevity ]
    

    When looking at that code, you’d think the “Result” of a function returning Variant is allways initialized to Unassigned by the calling party. Not true. If in the previous test we make the “X” variable a LOCAL variable (not global), the compiler no longer uses the two separate local temporary variables. So we’ve got two separate cases where the compiler generates different code. In other words, don’t make any assumptions, always assign Result.

    My guess about the different behavior: If the Variant variable can be accessed outside the current scope, as a global variable (or class field for that matter) would, the compiler generates code that uses the thread-safe @VarCopy function. If the variable is local to the function there are no multi-threading issues so the compiler can take the liberty to make direct assignments (no-longer calling @VarCopy).

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I'm using XmlPullParser to load some data gradually over http on mobile devices. Since
In a project that I've been involved with for many years, I've gradually evolved
Can php divide the page into small block and gradually appear? I divided my
I have a User model, the user can gradually insert information on their profile
I have gradually abandonned my offline emailer and switched to an online one, but
I have spent the last few months gradually tweaking my multi-monitor layout and shortcuts
I am a little confused as to the steps of reading a file into
I have a large codebase in a homebrew python framework. I'm going to be
I have a legacy application written in C , and i would like to
I'm getting tossed into an existing codebase, and part of the job is to

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.