Ian Branch 128 Posted April 4 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
Lars Fosdal 1793 Posted April 4 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 1 Share this post Link to post
JonRobertson 72 Posted April 4 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
Brandon Staggs 285 Posted April 4 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
Der schöne Günther 316 Posted April 5 (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 April 5 by Der schöne Günther 1 Share this post Link to post
JonRobertson 72 Posted April 5 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
Der schöne Günther 316 Posted April 5 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. 1 Share this post Link to post
Erwin Mouthaan 7 Posted April 5 A static code analysis with Pascal Analyzer for example, will help to find uninitialized variables. I just checked. It triggers a warnings report for variable Result which is referenced before set. https://ideasawakened.com/post/product-review-pascal-expert Share this post Link to post
Brandon Staggs 285 Posted April 5 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
Der schöne Günther 316 Posted April 5 (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 April 5 by Der schöne Günther Share this post Link to post
Brandon Staggs 285 Posted April 5 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
JonRobertson 72 Posted April 5 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
Brandon Staggs 285 Posted April 5 (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 April 5 by Brandon Staggs Share this post Link to post
Ian Branch 128 Posted April 5 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
JonRobertson 72 Posted April 5 5 minutes ago, Ian Branch said: A good idea. Where/how does one do that? Project Options, Building, Delphi Compiler, Hints and Warnings: Expand "Output warnings" and scroll down to "Variable might not have been initialized". Select the drop down and set it to "Error": Note there are *dozens* of warnings that you can change to errors. 1 Share this post Link to post
Ian Branch 128 Posted April 5 (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 April 5 by Ian Branch Share this post Link to post
JonRobertson 72 Posted April 6 4 hours ago, Ian Branch said: Cheers. It's a pity it has to be set per Project. Tks. If you want a "default" set of options to apply to each project, you can use Option Sets. Here are a couple of links: from-default-project-options-to-rad-studio-option-sets Option Sets Overview Share this post Link to post