Jump to content

Recommended Posts

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 by Skrim

Share this post


Link to post

As local variable it is not initialized, as global it is.

  • Thanks 1

Share this post


Link to post
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.

  • Thanks 1

Share this post


Link to post

Note that there is also a System.SysUtils.TryStrToFloat() function, along with many other TryStrToXXX() functions, you may find them handy.

  • Like 2
  • Thanks 1

Share this post


Link to post
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
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.

  • Like 1

Share this post


Link to post
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
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

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

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.

  • Thanks 1

Share this post


Link to post
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

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 by Stefan Glienke
  • Like 1

Share this post


Link to post
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
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
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
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 by dummzeuch

Share this post


Link to post
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 by Stefan Glienke
  • Like 2

Share this post


Link to post
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 by Brandon Staggs
  • Like 1

Share this post


Link to post
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
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;

 

  • Like 1

Share this post


Link to post
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
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

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

×