I've just been debugging a problem with a function that returns a string that has got me worried. I've always assumed that the implicit Result variable for functions that return a string would be empty at the start of the function call, but the following (simplified) code produced an unexpected result:
function TMyObject.GenerateInfo: string; procedure AppendInfo(const AppendStr: string); begin if(Result > '') then Result := Result + #13; Result := Result + AppendStr; end; begin if(ACondition) then AppendInfo('Some Text'); end;
Calling this function multiple times resulted in:
"Some Text"
the first time,
"Some Text" "Some Text"
the second time,
"Some Text" "Some Text" "Some Text"
the third time, etc.
To fix it I had to initialise the Result:
begin Result := ''; if(ACondition) then AppendInfo('Some Text'); end;
Is it necessary to initialise a string function result? Why (technically)? Why does the compiler not emit a warning "W1035 Return value of function 'xxx' might be undefined" for string functions? Do I need to go through all my code to make sure a value is set as it is not reliable to expect an empty string from a function if the result is not explicitly set?
I've tested this in a new test application and the result is the same.
procedure TForm1.Button1Click(Sender: TObject); var i: integer; S: string; begin for i := 1 to 5 do S := GenerateInfo; ShowMessage(S); // 5 lines! end;
String initialization is one of the basic parts of programming. String initialization means assigning a value to the variable before it's used in the java program. String initialization can be done in two ways: Object Initialization.
Initialize a string by passing a literal, quoted character array as an argument to the constructor. Initialize a string using the equal sign (=). Use one string to initialize another. These are the simplest forms of string initialization, but variations offer more flexibility and control.
out. println(monthString); In order to use a local variable in java it must be initialized to something even if that something is setting it equal to null .
This is not a bug, but "feature":
For a string, dynamic array, method pointer, or variant result, the effects are the same as if the function result were declared as an additional var parameter following the declared parameters. In other words, the caller passes an additional 32-bit pointer that points to a variable in which to return the function result.
I.e. your
function TMyObject.GenerateInfo: string;
Is really this:
procedure TMyObject.GenerateInfo(var Result: string);
Note "var" prefix (not "out" as you may expect!).
This is SUCH un-intuitive, so it leads to all kind of problems in the code. Code in question - just one example of results of this feature.
See and vote for this request.
We've run into this before, I think maybe as far back as Delphi 6 or 7. Yes, even though the compiler doesn't bother to give you a warning, you do need to initialize your string Result variables, for precisely the reason you ran into. The string variable is getting initialized -- it doesn't start as a garbage reference -- but it doesn't seem to get reinitialized when you expect it to.
As for why it happens... not sure. It's a bug, so it doesn't necessarily need a reason. We only saw it happen when we called the function repeatedly in a loop; if we called it outside a loop, it worked as expected. It looked like the caller was allocating space for the Result variable (and reusing it when it called the same function repeatedly, thus causing the bug), rather than the function allocating its own string (and allocating a new one on each call).
If you were using short strings, then the caller does allocate the buffer -- that's long-standing behavior for large value types. But that doesn't make sense for AnsiString. Maybe the compiler team just forgot to change the semantics when they first implemented long strings in Delphi 2.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With