Skrim 11 Posted October 27 (edited) var aNumber : Double; begin aNumber:=0; aNumber:=strtofloat(grid.Cells[3,arow]); ... ... Are floatvalues automatically initialized as 0 (zero)? Is the first code line unnecessary? If I understand the Help file correctly, global variables are and local variables are not? Edited October 27 by Skrim Share this post Link to post
Olli73 5 Posted October 27 As local variable it is not initialized, as global it is. 1 Share this post Link to post
aehimself 396 Posted October 27 1 hour ago, Skrim said: If I understand the Help file correctly, global variables are and local variables are not? That is correct. All local variables are uninitialized and might contain complete garbage until the first assignment. 1 hour ago, Skrim said: Is the first code line unnecessary? Without checking the source, StrToFloat has two options: either throw an exception or to return a value. The line after this assignment is only executed if no exception was thrown, therefore the local variable holds an actual value. Therefore, the variable := 0 is unnecessary in this case. 1 Share this post Link to post
Attila Kovacs 629 Posted October 27 Note that there is also a System.SysUtils.TryStrToFloat() function, along with many other TryStrToXXX() functions, you may find them handy. 2 1 Share this post Link to post
Gord P 14 Posted October 27 9 hours ago, Skrim said: Is the first code line unnecessary? I sure don't think so. Assuming something is initialized is a bit dangerous IMO. Share this post Link to post
Remy Lebeau 1403 Posted October 27 12 hours ago, aehimself said: Without checking the source, StrToFloat has two options: either throw an exception or to return a value. StrToFloat() does not have an option to return a default value. You need to use TryStrToFloat() for that. 1 Share this post Link to post
aehimself 396 Posted October 27 3 minutes ago, Remy Lebeau said: StrToFloat() does not have an option to return a default value. That's exactly what I meant. If no exceptions are thrown, the string was successfully converted and the return value will initialize the variable correctly. As the snipplet above contained no Try..Except or Try...Finally blocks it doesn't matter what would use the variable in question afterwards as it never gets executed. Share this post Link to post
Remy Lebeau 1403 Posted October 27 29 minutes ago, aehimself said: That's exactly what I meant. If no exceptions are thrown, the string was successfully converted and the return value will initialize the variable correctly. Sorry, I had misread your earlier message. Share this post Link to post
Charlie Heaps 2 Posted November 8 Dumb question - why would it NOT be a good idea for variables to be initialized by Delphi (e.g. to zero/blank/false) both locally and globally. I have always found it strange that they are not. What would it break if Embarcadero changed this? Or would it slow down code? Share this post Link to post
dummzeuch 1506 Posted November 8 3 hours ago, Charlie Heaps said: Dumb question - why would it NOT be a good idea for variables to be initialized by Delphi (e.g. to zero/blank/false) both locally and globally. I have always found it strange that they are not. What would it break if Embarcadero changed this? Or would it slow down code? It would indeed slow down the code. But I doubt that it would make much of a difference nowadays except under very special circumstances.. Share this post Link to post
Stefan Glienke 2009 Posted November 11 Why should the CPU waste time zeroing stuff that will be set shortly after anyway? Compilers are there to warn/error when any code path leads to a situation where a variable is not initialized. 1 Share this post Link to post
A.M. Hoornweg 144 Posted November 11 2 hours ago, Stefan Glienke said: Why should the CPU waste time zeroing stuff that will be set shortly after anyway? Compilers are there to warn/error when any code path leads to a situation where a variable is not initialized. As far as I know, when an object is created all its members are filled with zero. And for stack variables, all managed types are filled with zero upon entry of a method. However, wouldn't it actually save CPU time if Delphi simply wiped the local variables area of the stack upon entry of a method (a known fixed number of bytes - a simple REP STOSD will do) instead of determining which local variables are managed types and then wiping those individually? Share this post Link to post
Stefan Glienke 2009 Posted November 11 (edited) First, it's wrong to assume that all local variables reside on the stack, depending on optimization they might be in registers. Second, rep stosd is terribly slow for small sizes (see https://stackoverflow.com/a/33485055/587106 and also the discussions on this issue https://github.com/dotnet/runtime/issues/10744) Also, the Delphi compiler arranges managed local variables into one block that it zeroes (in many different and mostly terribly inefficient ways). Edited November 11 by Stefan Glienke 1 Share this post Link to post
A.M. Hoornweg 144 Posted November 12 11 hours ago, Stefan Glienke said: First, it's wrong to assume that all local variables reside on the stack, depending on optimization they might be in registers. Second, rep stosd is terribly slow for small sizes (see https://stackoverflow.com/a/33485055/587106 and also the discussions on this issue https://github.com/dotnet/runtime/issues/10744) Also, the Delphi compiler arranges managed local variables into one block that it zeroes (in many different and mostly terribly inefficient ways). I for one would find it an advantage if stuff like local pointer variables would default to NIL, it would make the language just a little bit more memory safe. Share this post Link to post
Stefan Glienke 2009 Posted November 12 2 hours ago, A.M. Hoornweg said: I for one would find it an advantage if stuff like local pointer variables would default to NIL, it would make the language just a little bit more memory safe. The main issue with memory safety in Delphi is not non-initialized local variables, which the compiler warns about, but use-after-free. Share this post Link to post
JonRobertson 72 Posted November 12 9 hours ago, A.M. Hoornweg said: I for one would find it an advantage if stuff like local pointer variables would default to NIL, it would make the language just a little bit more memory safe. That's an odd opinion, considering that a "pointer variable" or object reference with a nil value still results in an Access Violation if used before it is assigned a valid (allocated) memory reference. Using a local pointer variable before it is assigned a value is an error, regardless of whether the variable "defaulted to NIL". As Stefan stated, by not defaulting a value, the compile will give a warning (which I change to an error for every project). This code would not give a warning (silly example, but still): var MyForm: TForm := nil; MyForm.Show; Share this post Link to post
dummzeuch 1506 Posted November 12 (edited) 45 minutes ago, JonRobertson said: That's an odd opinion, considering that a "pointer variable" or object reference with a nil value still results in an Access Violation if used before it is assigned a valid (allocated) memory reference. var MyForm: TForm := nil; MyForm.Show; But you can easily check for nil, while that's not possible for "uninitialized". And you can also easily spot them in the debugger. Also, referencing a non-initialized object reference does not necessarily result in an access violation, while referencing nil definitely does. Edited November 12 by dummzeuch Share this post Link to post
Stefan Glienke 2009 Posted November 12 (edited) 1 hour ago, dummzeuch said: while referencing nil definitely does. Which - fun fact - does not happen on the method call (unless it's a virtual method) but when accessing any member inside of it. You could still have some method which does not access any member and it will not AV at all. We can argue all day about this - any runtime behavior one might slap onto it will not save the language from being inherently unsafe. It needs to be built into the language/compiler itself (Hi, Rust) Edited November 12 by Stefan Glienke 2 Share this post Link to post
Brandon Staggs 278 Posted November 12 (edited) 22 minutes ago, Stefan Glienke said: Which - fun fact - does not happen on the method call (unless it's a virtual method) but when accessing any member inside of it. You could still have some method which does not access any member and it will not AV at all. Yup, which is just one more reason why safety through automatic initialization is illusory. Edited November 12 by Brandon Staggs 1 Share this post Link to post
dummzeuch 1506 Posted November 13 11 hours ago, Stefan Glienke said: Which - fun fact - does not happen on the method call (unless it's a virtual method) but when accessing any member inside of it. You could still have some method which does not access any member and it will not AV at all. I have actually been using this "feature" when I needed an event handler but didn't have an object ready, by declaring a local variable of a simple class type declared just for this purpose, setting it to nil (just to shut up the compiler) and assigning its method to the event. That method simply doesn't do anything that requires self to have a value, so it works fine (it also must not be virtual). No constructor/destructor calls required and also no memory leak created. Alternatively one could create a plain procedure with the right signature, assign that to the code pointer of a TMethod record, leave the data pointer unassigned or set it to nil, and assign that record to the event using appropriate type casting. But that somehow feels hackier than the nil object instance. Share this post Link to post
Vandrovnik 214 Posted November 13 30 minutes ago, dummzeuch said: I have actually been using this "feature" when I needed an event handler but didn't have an object ready, by declaring a local variable of a simple class type declared just for this purpose, setting it to nil (just to shut up the compiler) and assigning its method to the event. That method simply doesn't do anything that requires self to have a value, so it works fine (it also must not be virtual). No constructor/destructor calls required and also no memory leak created. Alternatively one could create a plain procedure with the right signature, assign that to the code pointer of a TMethod record, leave the data pointer unassigned or set it to nil, and assign that record to the event using appropriate type casting. But that somehow feels hackier than the nil object instance. What about a class procedure? type tTest = class(tObject) public class procedure MyFormShow(Sender: TObject); end; ... self.OnShow:=tTest.MyFormShow; 3 Share this post Link to post
dummzeuch 1506 Posted November 13 11 minutes ago, Vandrovnik said: What about a class procedure? type tTest = class(tObject) public class procedure MyFormShow(Sender: TObject); end; ... self.OnShow:=tTest.MyFormShow; Does that compile? Share this post Link to post
Vandrovnik 214 Posted November 13 8 minutes ago, dummzeuch said: Does that compile? Yes, it does (Delphi 12.2). Share this post Link to post
Vandrovnik 214 Posted November 13 9 minutes ago, dummzeuch said: Does that compile? I just did not test, whether it works O:-) Share this post Link to post
A.M. Hoornweg 144 Posted November 13 1 hour ago, dummzeuch said: Does that compile? Just declare class procedure MyFormShow(Sender: TObject); STATIC; That way the method does not have a hidden "self" parameter. Having no "self" parameter turns the class method into a regular procedure inside the namespace tTest (it is no longer a "procedure of object"). Static class methods are unable to access any members or methods that require a "self" parameter. Share this post Link to post