Forum > General

Inherited fail

(1/1)

jollytall:
Classes have a rarely used but nice feature in their constructor: fail. If anywhere in the constructor fail is called it means an immediate exit AND the fact that the class instance is not created and the return value is set to nil.
So if I have:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---MyClass := tMyClass.Create; // exit with a failif not assigned(MyClass) then  writeln('Instance not created');it works as it should.

Now I have:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---constructor tMyClass2;  begin  inherited Create; // this one exits with a fail  // How can I catch it here????  end;In my tests I found that (a) the constructor of tMyClass exits with fail all right, (b) the constructor of tMyClass2 does NOT exit immediately (i.e. it does not behave like a raised exception that goes up in the calling chain), but continues with the next instruction (c) the Self parameter is not nil after the inherited Create (not even if I explicitly set it to nil in the inherited constructor before fail).

So, I could not figure out if the inherited Create was successful or not. Any solution?

jamie:
base classes have no create to inherit from.

The fact that SELF isn't nil indicates it was created.

Unless you are talking about something else I don't know.

ASerge:

--- Quote from: jollytall on November 30, 2021, 06:24:21 pm ---So, I could not figure out if the inherited Create was successful or not. Any solution?

--- End quote ---
Use exceptions.

1. The Fail procedure in Delphi is valid only for old objects (in FPC also for classes).
2. The Fail procedure fails %) with inheritance in FPC. Example:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---{$IFDEF FPC}  {$MODE OBJFPC}  {$LONGSTRINGS ON}{$ENDIF}{$APPTYPE CONSOLE} uses SysUtils; type  PBase = ^TBase;  TBase = object    constructor Init;    destructor Done;  end;   PDescendant = ^TDescendant;  TDescendant = object(TBase)    constructor Init;  end; constructor TDescendant.Init;begin  Writeln('  begin TDescendant.Create');  inherited;  Writeln('  TDescendant.Create end');end; constructor TBase.Init;begin  Writeln('    begin TBase.Create');  Fail;  Writeln('    TBase.Create end');end; destructor TBase.Done;begin  Writeln('  TBase.Done');end; procedure Test;var  P: PBase;begin  WriteLn('begin');  P := New(PDescendant, Init);  if P = nil then    Writeln('  P is nil')  else    try      Writeln('  P is not nil!');    finally      Dispose(P, Done);    end;  WriteLn('end');end; begin  Test;  Readln;end.
In FPC:

--- Quote ---begin
  begin TDescendant.Create
    begin TBase.Create
  TDescendant.Create end
  P is not nil!
  TBase.Done
end
--- End quote ---

In Delphi:

--- Quote ---begin
  begin TDescendant.Create
    begin TBase.Create
  TDescendant.Create end
  P is nil
end
--- End quote ---

jollytall:
 @jamie: I am not sure I understand your reply. As ASerge details, base classes (and base objects) can have Create and it can be inherited. Self is indeed set, but that is actually the problem.

@ASerge: Thanks for the detailed answer.
Exceptions: Yes i can use that, but I can also have a boolean field to check, but I thought that fail is so elegant.

1. Fail in Classes: It works in FPC even in mode delphi. If it does not work in "real" Delphi, it is a bit of compatibility issue, although to the right direction (more allowed).

2. If Fail fails, isn't it a failure (OK, a bug, but could not resist, sorry)? However i do not know what would the correct way be to work. As your example shows even the Delphi way is wrong. 'TDescendant.Create end' is reached, meaning that code after the inherited line is executed, while the pointer is probably already zero. I cannot check (I do not use Windows / Delphi), but I can imagine that as the pointer is nil, any access of fields there is a GP fault. The correct probably would be that not even 'TDescendant.Create end' is reached, like with exceptions.

Last, but not least, your Delphi approach is not the same in FPC Delphi mode even for old objects (another small compatibility difference).

ASerge:
Sorry, my example was incorrect. The object size is zero, so Delphi always returns nil in this case (unlike FPC). If you add some field, the behavior of Delphi will be the same as FPC. Fail will work only for one level of inheritance: for PBase, but not for PDescendant.

Navigation

[0] Message Index

Go to full version