Jump to content
Ian Branch

State of an uninitialised variables..

Recommended Posts

Hi Team,

This is as much to reinforce with me as it is info that may help others.

 

"Local variables are actually not initialized, but global variables and object fields are initialized to zero (which means 'false' for boolean variables).

Therefore you always have to initialize local variables yourself, compiler even generates a warning if you don't."

 

I got caught out with an inline variable.  var lTest: boolean;

I incorrectly assumed ite defaulted to False.

This is not so, in fact in my tests it seems to default to TRUE.

However, I won't bank on that and will allways initialise local variables now. 

No, I never noticed the warning, or if I did I ignored it.  😞

 

Ian

Share this post


Link to post

Variable not initialized - I set that one to raise a compile error - because those WILL bite you.

Also, you will get that if you init the variable inside a try block, instead of before the block.

 

Hints are often nearly as important as warnings. 

 

Value never used can f.x. mean that

  • you are referring to the wrong variable elsewhere
  • you are mistakenly replacing the value elsewhere before the one you initially set could be used
  • or, you didn't need to set that value because it would have been set elsewhere anyways

 

Share this post


Link to post
41 minutes ago, Lars Fosdal said:

Variable not initialized - I set that one to raise a compile error - because those WILL bite you.

I do as well. I even initialize strings and arrays. Although I have not seen this occur in years, I had an issue, around 15 years ago, in a Delphi 6 project where a local string variable was not initialized to empty string.

Share this post


Link to post
1 minute ago, JonRobertson said:

I do as well. I even initialize strings and arrays. Although I have not seen this occur in years, I had an issue, around 15 years ago, in a Delphi 6 project where a local string variable was not initialized to empty string.

There is no reason to initialize dynamic arrays or strings. If that is broken in the compiler you have bigger problems.

 

For example, if you are forced to initialize a string to an empty string, then by definition you will end up freeing the invalid string. Better to figure out the actual cause of the problem.

Share this post


Link to post
Posted (edited)

Although he explicitly said local variable, it could probably have been something like this:

program Project1;

function getText(const txt: String): String;
begin
	// Incorrectly assumes "Result" got 
	// initialized to an empty string
	Result := Result + txt;
end;

begin
	var text: String;
	text := getText('This should not be visible');
	text := getText('Hello');
	
	// Outputs "This should not be visibleHello"
	WriteLn(text); 
end.

 

Edited by Der schöne Günther
  • Thanks 1

Share this post


Link to post
8 hours ago, Der schöne Günther said:

it could probably have been something like this

I do believe our "issue" was with a String return value rather than a local variable. It amazes me that after using Delphi for 28 years, there are still things, even basic features, that I haven't learned.

 

Thank you for your post, which led to a search, then to so initialise-string-function-result, and then to this in the docs:

  • 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.

Share this post


Link to post
19 minutes ago, JonRobertson said:

It amazes me that after using Delphi for 28 years, there are still things, even basic features, that I haven't learned.

I wouldn't really call those features - Rather oddities, quirks or flat-out defects 😬

 

You can hardly blame yourself for not expecting something like that.

  • Like 1

Share this post


Link to post
10 hours ago, Der schöne Günther said:

Although he explicitly said local variable, it could probably have been something like this:

The issue here is that Result does not come into scope as your function executes, it already came into scope before your function was called. (Thankfully, it also doesn't go out of scope when your function exits, or your caller would not be able to use the result!) So in this case, you should not have a code path that doesn't explicitly set the Result variable, since you don't know if your caller used the variable after it was initialized or not), but it's not a question of initialization.

Share this post


Link to post
Posted (edited)
27 minutes ago, Brandon Staggs said:

you should not have a code path that doesn't explicitly set the Result variable

Yes, but we're just mere humans, and we don't even have a compiler that will help us by generating a warning.

 

Even the gods from Embarcaddero occasionally trip over this, here is an example straight from the RTL itself:

https://quality.embarcadero.com/browse/RSP-18300

Edited by Der schöne Günther

Share this post


Link to post
12 minutes ago, Der schöne Günther said:

Yes, but we're just mere humans, and we don't even have a compiler that will help us by generating a warning.

Agreed that the compiler should let us know if we don't set Result in a function regardless of the result type.

Share this post


Link to post
25 minutes ago, Brandon Staggs said:

Agreed that the compiler should let us know if we don't set Result in a function regardless of the result type.

Agreed.

 

I still think the code demonstrated in the report (and the example posted by Der schöne Günther) is unexpected behavior. 

		objectAsString := 'Hello World';
		objectAsString := TJson.Format(objectAsJson);
 
		WriteLn(objectAsString); // << It is "Hello World{}" (not including linebreaks)

I would not expect 150 to be written to the console for this code:

function GetAmount: Integer;
begin
  Result := 50;
end;

begin
  var i: Integer := 100;
  i := GetAmount;
  writeln(i);
end.

The compiler even hints that the initial value is never used.

[dcc32 Hint] H2077 Value assigned to 'i' never used

 

Share this post


Link to post
Posted (edited)

 

36 minutes ago, JonRobertson said:

Agreed.

 

I still think the code demonstrated in the report (and the example posted by Der schöne Günther) is unexpected behavior. 


		objectAsString := 'Hello World';
		objectAsString := TJson.Format(objectAsJson);
 
		WriteLn(objectAsString); // << It is "Hello World{}" (not including linebreaks)

I would not expect 150 to be written to the console for this code:


function GetAmount: Integer;
begin
  Result := 50;
end;

begin
  var i: Integer := 100;
  i := GetAmount;
  writeln(i);
end.

The compiler even hints that the initial value is never used.


[dcc32 Hint] H2077 Value assigned to 'i' never used

 

The assignment operator := certainly signals in my mind that I want to replace the value of the variable with whatever is on the right side. I think someone designing a function should be aware of that and ensure that it is the case, if they are returning managed types. That being said, there may be cases where appending/modifying the Result variable is useful. I'd consider it obfuscated code, or a hack at best.

 

However, I don't agree that Der schöne Günther's code above is unexpected behavior. It is exactly what I would expect reading the code. It may be puzzling at first but it is not a language or compiler flaw. The error was made by whoever wrote the code for the function.

 

Still, I agree a compiler warning would be useful here.

Edited by Brandon Staggs

Share this post


Link to post
On 4/5/2024 at 6:46 AM, Lars Fosdal said:

Variable not initialized - I set that one to raise a compile error - because those WILL bite you.

A good idea.  Where/how does one do that?

Share this post


Link to post
5 minutes ago, Ian Branch said:

A good idea.  Where/how does one do that?

Project Options, Building, Delphi Compiler, Hints and Warnings:

 

image.thumb.png.ffde00f5babfd196830ab614ca8e6bdc.png

 

Expand "Output warnings" and scroll down to "Variable might not have been initialized". Select the drop down and set it to "Error":

 

image.thumb.png.d28ca6200ba093e3e86bb82ab32eff8f.png

 

Note there are *dozens* of warnings that you can change to errors.

 

 

  • Thanks 1

Share this post


Link to post
Posted (edited)
6 minutes ago, JonRobertson said:

Project Options, Building, Delphi Compiler, Hints and Warnings:

Cheers.  It's a pity it has to be set per Project.

Tks.

Edited by Ian Branch

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×