View Issue Details

IDProjectCategoryView StatusLast Update
0029334FPCCompilerpublic2020-01-24 10:08
ReporterKazantsev AlexeyAssigned To 
PrioritynormalSeverityminorReproducibilityalways
Status newResolutionopen 
Product Version3.1.1Product Build32843 
Target VersionFixed in Version 
Summary0029334: Incorrect order of class constructors calls
DescriptionCompiler don't care of ordering calls of class constructors.
Steps To Reproduceprogram fpc_class_constructor_incorrect_calling_order;

{$mode delphiunicode}

type

  trec = record

    class var FFactor : double;

    type

     tnestedrec1 = record
       class var FFrequency : Int64;
       class constructor InitializeClass;
     end;

     tnestedrec2 = record
       class var FFrequency : Int64;
       class constructor InitializeClass;
     end;

   class constructor InitializeClass;

  end;

{ trec.tnestedrec1 }

class constructor trec.tnestedrec1.InitializeClass;
begin
  FFrequency := 1000;
  writeln('nestedrec1.FFrequency: ', FFrequency);
end;

{ trec.tnestedrec2 }

class constructor trec.tnestedrec2.InitializeClass;
begin
 FFrequency := 1000000;
 writeln('nestedrec2.FFrequency: ', FFrequency);
end;

{ trec }

class constructor trec.InitializeClass;
begin
 writeln('trec.InitializeClass');

 // exception, because tnestedrec1 (and nestedrec2) still was not initialized
 FFactor := tnestedrec2.FFrequency / tnestedrec1.FFrequency;
end;

begin

 writeln('rec.FFactor: ', trec.FFactor);
 readln;

end.
TagsNo tags attached.
Fixed in Revision
FPCOldBugId
FPCTarget-
Attached Files

Relationships

related to 0027185 closedMichael Van Canneyt In nested classes, class constructor Create and class destructor Destroy aren't called. 
related to 0036623 new Compiler always call class constructors even if classes are not used 

Activities

Kazantsev Alexey

2016-01-04 14:50

reporter  

fpc_class_constructor_incorrect_calling_order.lpr (1,190 bytes)

Sven Barth

2016-01-04 22:05

manager   ~0088625

Outer classes are initialized before nested classes and the other way round for finalization. This is Delphi compatible and documented (here: http://www.freepascal.org/docs-html/current/ref/refsu30.html#x80-1020006.5.5 ). See also the related bug report.

About classes being initalized independantly of being used AFAIK this is by design. At least the compiler is not able to strip away the code if the class is not used. And maybe sometimes that isn't even intended by the user...

Regards,
Sven

Kazantsev Alexey

2016-01-04 22:28

reporter   ~0088626

>This is Delphi compatible

This is not Delphi compatible, because (http://docwiki.embarcadero.com/RADStudio/Seattle/en/Methods#Class_Constructors):
"Note: Even though the compiler takes care of ordering the initialization of classes, in some complex scenarios, ordering may become random. This happens when the class constructor of a class depends on the state of another class that, in turn, depends on the first class."

Maciej Izak

2016-01-04 22:38

reporter   ~0088627

Last edited: 2016-01-04 22:38

View 2 revisions

About second point you are right, this is bug: "Compiler always call class constructors even if classes nowhere was used".

side note: Delphi compiler has {$STRONGLINKTYPES ON} to achieve this behavior.

Kazantsev Alexey

2016-01-04 22:48

reporter   ~0088628

About second point, this main goal of class constructors (same link):
"class constructors have the benefit of helping the compiler decide which classes should be included into the final binary file and which should be removed from it"

Sven Barth

2016-01-04 23:06

manager   ~0088632

@Kazantsev:
Regarding ordering: well, at least /I/ won't fix this anytime soon. I've already enough other topics on my plate. If someone else steps up for this... be my guest.

Regarding smart linking: this means that if there's a class constructor then the class will be linked in. Otherwise the expression "helping the compiler decide" makes no sense.

@Maciej: at least judging from the documentation this switch does not apply to classes with class constructors/destructors as - in their speak - they have strong fixups already due to the initialization/finalization, not a merely weak one.

Regards,
Sven

Kazantsev Alexey

2016-01-04 23:43

reporter   ~0088637

Last edited: 2016-01-05 00:16

View 2 revisions

>Otherwise the expression "helping the compiler decide" makes no sense.

Class can have the class constructor, but he will be invoked only in that case if the class is used somewhere, otherwise such class will be excluded from a final image. In it the basic difference from initialization section, when the code of a class in any case will be included in a final image without dependence from that the class whether or not is used somewhere.

About {$STRONGLINKTYPES ON}: this option works on classes with the class constructor, but only if they are in separate units (not main program). I have checked up.

Thaddy de Koning

2017-08-31 16:01

reporter   ~0102536

No! a class constructor is called when it is *defined* somewhere in working code and parsed. The current behavior is as I expect.
That's because casting to it is legal. It does not need to be used.

Serge Anvarov

2017-09-01 13:53

reporter   ~0102560

As can be seen from the documentation (https://www.freepascal.org/docs-html/current/ref/refsu29.html#x80-1020006.5.5), this behavior is well documented:
The class constructor/destructor is called irrespective of the use of the class: even if a class is never used, the constructor and destructor are called anyway.
There is no guaranteed order in which the class constructors or destructors are called. For nested classes, the only guaranteed order is that the constructors of nested classes are called after the constructor of the encompassing class is called, and for the destructors the opposite order is used.

Kazantsev Alexey

2017-09-01 14:56

reporter   ~0102565

>The class constructor/destructor is called irrespective of the use of the class: even if a class is never used, the constructor and destructor are called anyway.

In this case, there is no point in class constructors.

Thaddy de Koning

2017-09-01 17:49

reporter   ~0102570

Last edited: 2017-09-01 17:51

View 3 revisions

Well, very useful:

program Project1;
{$apptype console}{$mode objfpc}
type
  TSomeClass = class
  public
    Class constructor create;
  end;
  
  class constructor TsomeClass.create;
  begin
    writeln('useful');
  end;
  
begin
// look, maw, no hands...
end.

Kazantsev Alexey

2017-09-01 19:11

reporter   ~0102572

Shit. Do use unit with initialization and get same.

Thaddy de Koning

2017-09-02 10:08

reporter   ~0102585

It is not the same. But it can have a similar effect in this simple example.

Ondrej Pokorny

2020-01-24 09:26

developer   ~0120699

I agree with Alexey. The calling-order point is not really that important because nested classes have other bugs in FPC, so they are to be used with care anyway. But the smart-linking point is very much needed.

Because they are different bugs, I allowed myself to edit this report's description to match the summary (=keep only the 1st point) and create a separate bug report for the second point that I also linked to as related.

Thaddy de Koning

2020-01-24 09:42

reporter   ~0120700

Last edited: 2020-01-24 09:46

View 2 revisions

As per my example, I consider this a feature and not a bug.
But the concept of executing code without a program body is very strange indeed....very, very strange...
So maybe you are right.

Thaddy de Koning

2020-01-24 09:54

reporter   ~0120703

Last edited: 2020-01-24 10:08

View 4 revisions

And it should not be allowed: both initialization and class constructors with an empty program body is counter intuitive.
It is also potentially dangerous, because a whole program can be hidden from sight unless read by experienced programmers.
Scenario: some units with initialization, some classes with class constructors, compile empty program and it is actually executed on run....without main...

This should be discussed.
My insight has changed in the past three years. Such things should not happen.

Issue History

Date Modified Username Field Change
2016-01-04 14:50 Kazantsev Alexey New Issue
2016-01-04 14:50 Kazantsev Alexey File Added: fpc_class_constructor_incorrect_calling_order.lpr
2016-01-04 22:05 Sven Barth Note Added: 0088625
2016-01-04 22:05 Sven Barth Relationship added related to 0027185
2016-01-04 22:28 Kazantsev Alexey Note Added: 0088626
2016-01-04 22:38 Maciej Izak Note Added: 0088627
2016-01-04 22:38 Maciej Izak Note Edited: 0088627 View Revisions
2016-01-04 22:48 Kazantsev Alexey Note Added: 0088628
2016-01-04 23:06 Sven Barth Note Added: 0088632
2016-01-04 23:43 Kazantsev Alexey Note Added: 0088637
2016-01-05 00:16 Kazantsev Alexey Note Edited: 0088637 View Revisions
2017-08-31 16:01 Thaddy de Koning Note Added: 0102536
2017-09-01 13:53 Serge Anvarov Note Added: 0102560
2017-09-01 14:56 Kazantsev Alexey Note Added: 0102565
2017-09-01 17:49 Thaddy de Koning Note Added: 0102570
2017-09-01 17:50 Thaddy de Koning Note Edited: 0102570 View Revisions
2017-09-01 17:51 Thaddy de Koning Note Edited: 0102570 View Revisions
2017-09-01 19:11 Kazantsev Alexey Note Added: 0102572
2017-09-02 10:08 Thaddy de Koning Note Added: 0102585
2020-01-24 09:23 Ondrej Pokorny Relationship added related to 0036623
2020-01-24 09:26 Ondrej Pokorny Description Updated View Revisions
2020-01-24 09:26 Ondrej Pokorny Steps to Reproduce Updated View Revisions
2020-01-24 09:26 Ondrej Pokorny FPCTarget => -
2020-01-24 09:26 Ondrej Pokorny Note Added: 0120699
2020-01-24 09:42 Thaddy de Koning Note Added: 0120700
2020-01-24 09:46 Thaddy de Koning Note Edited: 0120700 View Revisions
2020-01-24 09:54 Thaddy de Koning Note Added: 0120703
2020-01-24 10:01 Thaddy de Koning Note Edited: 0120703 View Revisions
2020-01-24 10:04 Thaddy de Koning Note Edited: 0120703 View Revisions
2020-01-24 10:08 Thaddy de Koning Note Edited: 0120703 View Revisions