Recent

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


GetMem

  • Hero Member
  • *****
  • Posts: 3673
@ BrainChemistry
Quote
That is exactly the case, hence it is unfortunately no option to check the condition outside the constructor.
OK. I know this is not your fault, however the whole logic seems strange to me. After all set and done, the programmer who calls your class, still has to check if the instance is nil. What is the point? I'm I missing something?

julkas

  • Hero Member
  • *****
  • Posts: 584
  • KISS principle / Lazarus 2.0.6 / FPC 3.0.4
procedure mulu64(a, b: QWORD; out clo, chi: QWORD); assembler;
asm
  mov rax, a
  mov rdx, b
  mul rdx
  mov [clo], rax
  mov [chi], rdx
end;

BrainChemistry

  • Jr. Member
  • **
  • Posts: 70
@ BrainChemistry
Quote
That is exactly the case, hence it is unfortunately no option to check the condition outside the constructor.
OK. I know this is not your fault, however the whole logic seems strange to me. After all set and done, the programmer who calls your class, still has to check if the instance is nil. What is the point? I'm I missing something?

I do not fully understand your confusion about that. The programmer using the unit may accidently use wrong arguments (nil pointer, integers out of bounds, and so on) for my classes, in these cases, my class will react accordingly and testable. What the programmer makes from this, is his own responsibility, I guess. :D

Although, in the constructor, C functions from external libraries (which I do not maintain) are called , so even if the input is checked to seem perfectly valid, the constructor may lead to a fail. And this is testable now.

https://www.freepascal.org/docs-html/rtl/system/fail.html
If you don't want Delphi compatibility it's ok.

I want Delphi compatibility, and to be honest, on examining your links, I was kind of disappointed. Maybe I will introduce a compiler switch for Delphi later. For now, I will stay with FPC's way of handling it, which seems more convenient to me. Thanks for the hint though!

GetMem

  • Hero Member
  • *****
  • Posts: 3673
@BrainChemistry
The programmer using the unit has two solutions:
1. Check if the pointer is valid then create your class
2. Feed invalid pointers to the constructor, then check if the class explodes

Which is better? I mean why burn down the house when you can read the label:" high explosive".

BrainChemistry

  • Jr. Member
  • **
  • Posts: 70
@GetMem
Well, of course the programmer should make sure to input valid data for the class beforehand. But what if the programmer misses something at the validity check, or the seemingly valid data is rejected by the external C functions because they unexpectedly consider it as invalid for some reason? In these (hopefully very rare) cases the creation process should be aborted in a clean way.

eljo

  • Sr. Member
  • ****
  • Posts: 358
@GetMem
Well, of course the programmer should make sure to input valid data for the class beforehand. But what if the programmer misses something at the validity check, or the seemingly valid data is rejected by the external C functions because they unexpectedly consider it as invalid for some reason? In these (hopefully very rare) cases the creation process should be aborted in a clean way.
the disagreement is what is considered a "clean way". In my opinion a hard exception at creation with a clear message eg "Par1 is empty" is far easier to track and debug than a silent fail with no indication what or why it failed. I think that is what GetMem says as well.

PascalDragon

  • Hero Member
  • *****
  • Posts: 1523
  • Compiler Developer
@GetMem
Well, of course the programmer should make sure to input valid data for the class beforehand. But what if the programmer misses something at the validity check, or the seemingly valid data is rejected by the external C functions because they unexpectedly consider it as invalid for some reason? In these (hopefully very rare) cases the creation process should be aborted in a clean way.

The clean, Object Pascal way is indeed raising an exception. While Fail will work, it will only work inside the constructor itself. If you have a call to some setup method (for example shared between multiple constructors), you can't use Fail.

more idiocy ( I am mad enough thank you..(true))
Quote
raise an exception
In a constructor?, really???
Then you should also handle the exception inside the constructor....

No, raising an exception inside the constructor is an explicitly supported concept of Object Pascal. The compiler inserts implicit exception handling code to handle this case gracefully (and have the constructor return Nil). It's a major improvement compared to TP style objects which only had Fail.

Thaddy

  • Hero Member
  • *****
  • Posts: 10119
No, raising an exception inside the constructor is an explicitly supported concept of Object Pascal. The compiler inserts implicit exception handling code to handle this case gracefully (and have the constructor return Nil). It's a major improvement compared to TP style objects which only had Fail.
That may be the case but those exceptions should still be handled inside the constructor, since all kinds of managed code may be initialized. With all the mayhem associated with it. Add a try/finally is enough to blow that up.
As Allen Bauer wrote (paraphrased) handle as soon as possible, not raise..
I am more like donkey than shrek

BrunoK

  • Sr. Member
  • ****
  • Posts: 250
  • Retired programmer
Concerning the original poster code
there is a code error in the sense that FreeAndNil will nether be executed because exit precedes it.

given APar cannot be modified, since there is no way to change it as per constructor definition, the following code will cover the situation.
Code: Pascal  [Select][+][-]
  1. constructor Test.Create(APar: Pointer);
  2. begin
  3.   if not Assigned(APar) then begin
  4.     FreeAndNil(Self);
  5.     exit;
  6.   end
  7.   else
  8.     inherited Create;
  9.   //...
  10. end;

Thaddy

  • Hero Member
  • *****
  • Posts: 10119
Correct. Tnx for this example.
I am more like donkey than shrek

PascalDragon

  • Hero Member
  • *****
  • Posts: 1523
  • Compiler Developer
No, raising an exception inside the constructor is an explicitly supported concept of Object Pascal. The compiler inserts implicit exception handling code to handle this case gracefully (and have the constructor return Nil). It's a major improvement compared to TP style objects which only had Fail.
That may be the case but those exceptions should still be handled inside the constructor, since all kinds of managed code may be initialized. With all the mayhem associated with it. Add a try/finally is enough to blow that up.
As Allen Bauer wrote (paraphrased) handle as soon as possible, not raise..

It makes no sense to handle an exception that you yourself raised to leave the constructor... I agree about exceptions that some called method raises, but this is about something like the following:

Code: Pascal  [Select][+][-]
  1. constructor TMyClass.Create(aArg: TSomeOtherClass);
  2. begin
  3.   if not Assigned(aArg) then
  4.     raise EArgumentNilException.Create('aArg is Nil');
  5.   // ...
  6. end;

ASerge

  • Hero Member
  • *****
  • Posts: 1563
This is very, very bad if the constructor returns nil when problems occur, and does not raise an exception. Everywhere and everywhere it is assumed that if the constructor was completed, then the object was created. If you still decide to do this, then write comment with large letters "HERE A BAD CONSTRUCTION IS USED, ATTENTION, THE OBJECT MAY BE NIL!"

PascalDragon

  • Hero Member
  • *****
  • Posts: 1523
  • Compiler Developer
This is very, very bad if the constructor returns nil when problems occur, and does not raise an exception. Everywhere and everywhere it is assumed that if the constructor was completed, then the object was created. If you still decide to do this, then write comment with large letters "HERE A BAD CONSTRUCTION IS USED, ATTENTION, THE OBJECT MAY BE NIL!"
This as well. ;D

MarkMLl

  • Hero Member
  • *****
  • Posts: 870
This is very, very bad if the constructor returns nil when problems occur, and does not raise an exception. Everywhere and everywhere it is assumed that if the constructor was completed, then the object was created. If you still decide to do this, then write comment with large letters "HERE A BAD CONSTRUCTION IS USED, ATTENTION, THE OBJECT MAY BE NIL!"
This as well. ;D

HERE BE PASCALDRAGONS! :-)

Seriously, though, what else would one expect to happen if there isn't provision for an explicit success or failure result? It's been the case for a long time that something like an out-of-memory error results in a nil pointer result from heap allocation... the only real alternative would be for TObject to be extended with a property that is false until the constructor has returned successfully.

MarkMLl


Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.

 

TinyPortal © 2005-2018