Recent

Author Topic: [SOL.]How to leave constructor early (and destroy instance) if condition is met?  (Read 4945 times)

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Ah, correction: the constructor returning Nil is in most cases caught by the following code accessing the object and which is usually part of a resource protection block:

Code: Pascal  [Select][+][-]
  1. var
  2.   o: TMyClass;
  3. begin
  4.   o := TMyClass.Create;
  5.   try
  6.     o.DoSomething;
  7.   finally
  8.     o.Free;
  9.   end;
  10. end;

Under the assumption that DoSomething accesses the instance in some way (e.g. VMT call, accessing a field, etc.) this will crash if the constructor returned Nil, so all is nice and well. And if the constructor decides to raise an exception that is fine as well as the whole resource protection block will be skipped then. What is problematic however is this:

Code: Pascal  [Select][+][-]
  1. procedure Test;
  2. var
  3.   o: TMyClass;
  4. begin
  5.   try
  6.     o := TMyClass.Create;
  7.     o.DoSomething;
  8.   finally
  9.     o.Free;
  10.   end;
  11. end;

If the constructor raises an exception (which is allowed after all!) this will result in o having a random value (it's a variable on the stack after all) and thus will result in a nested exception when the code in the finally block is executed. The solution is to either move the constructor call before the resource protection block or to manually initialize o to Nil as the assignment won't be executed if the constructor raises an exception.

However it is the case that Object Pascal code usually does not check if a valid class instance was returned, relying on the above concepts instead.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Even worse:

Code: [Select]
    procedure Test;

    begin
        with TMyClass.Create do
            DoSomething() and Free
    end;

MarkMLl

MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Even worse:

Code: [Select]
    procedure Test;

    begin
        with TMyClass.Create do
            DoSomething() and Free
    end;

The only part that is worse here is the missing resource protection block. Otherwise it's equivalent to the standard case:

Code: Pascal  [Select][+][-]
  1. with TMyClass.Create do
  2.   try
  3.     DoSomething;
  4.   finally
  5.     Free;
  6.   end;

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Even worse:

Code: [Select]
    procedure Test;

    begin
        with TMyClass.Create do
            DoSomething() and Free
    end;

The only part that is worse here is the missing resource protection block. Otherwise it's equivalent to the standard case:

Code: Pascal  [Select][+][-]
  1. with TMyClass.Create do
  2.   try
  3.     DoSomething;
  4.   finally
  5.     Free;
  6.   end;

Except that the use of  with  means that there isn't an instantiation that can be checked by a debugger. I trust that you don't condone that style.

MarkMLl

MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Except that the use of  with  means that there isn't an instantiation that can be checked by a debugger. I trust that you don't condone that style.

This is only a question of correctly generated debug information and the debugger/IDE handling it correcty (currently either one or both are not the case, at least with DWARF) as internally there is a temporary variable.

And as I said it's a valid concept that's even used in the RTL here and there.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Except that the use of  with  means that there isn't an instantiation that can be checked by a debugger. I trust that you don't condone that style.

This is only a question of correctly generated debug information and the debugger/IDE handling it correcty (currently either one or both are not the case, at least with DWARF) as internally there is a temporary variable.

Well, you might possibly recall that I've been saying for years that  with  would benefit from an explicit "shorthand" name, and possibly having the implicit name standardised would be an advantage.

Code: [Select]
procedure Test;

    begin
        with newInstance= TMyClass.Create do
            newInstance.DoSomething() and newInstance.Free
    end;

// Not really a good example, it's obviously no advantage until the  with  applies to a complex sequence of fields and dereferences.



Quote
And as I said it's a valid concept that's even used in the RTL here and there.

"Even"? I can assure you that I'm keenly aware of that, having had to single-step through bits of it.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Except that the use of  with  means that there isn't an instantiation that can be checked by a debugger. I trust that you don't condone that style.

This is only a question of correctly generated debug information and the debugger/IDE handling it correcty (currently either one or both are not the case, at least with DWARF) as internally there is a temporary variable.

Well, you might possibly recall that I've been saying for years that  with  would benefit from an explicit "shorthand" name, and possibly having the implicit name standardised would be an advantage.

Code: [Select]
procedure Test;

    begin
        with newInstance= TMyClass.Create do
            newInstance.DoSomething() and newInstance.Free
    end;

// Not really a good example, it's obviously no advantage until the  with  applies to a complex sequence of fields and dereferences.


An explicitely declared, local variable fullfills the same purpose. And we won't make an exception for inline variables only for with.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
An explicitely declared, local variable fullfills the same purpose. And we won't make an exception for inline variables only for with.

Shucks. I was hoping you wouldn't notice :-) :-) :-)

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018