View Issue Details

IDProjectCategoryView StatusLast Update
0024848FPCCompilerpublic2017-07-07 04:28
ReporterMaciej Izak Assigned ToSven Barth  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Product Version2.7.1 
Fixed in Version3.0.0 
Summary0024848: Class constructor undefined symbol in generic class
DescriptionI can't compile attached code:

program project18;

{$mode delphi}

type
  TFoo<T> = class
    class constructor Create;
  end;

class constructor TFoo<T>.Create;
begin
end;

begin
end. // Error: Undefined symbol: P$PROJECT18$_$TFOO$1_$__$$_create
Tagsgenerics
Fixed in Revision25234
FPCOldBugId
FPCTarget
Attached Files

Relationships

related to 0028911 new "class var" is broken for generics 
related to 0025599 closedSven Barth Generic class constructor don't work correctly 
related to 0027206 resolvedSven Barth [Patch] Christmas gift by FreeSparta : Generics.Collections 

Activities

Maciej Izak

2013-08-09 15:27

reporter  

project18.lpr (235 bytes)

Sven Barth

2013-08-11 13:24

manager   ~0069334

It was easy to fix, but please be aware that using class constructors/destructors and also class fields can have potential side effects in generics: If you specialize a generic TFoo which has a class constructor with Integer in unit A and also with Integer in unit B then both units will execute the class constructors at the beginning (same for class destructors). And class variables won't be shared between the two specializations either.
To avoid this you'd need to specialize the generic in one unit (explicitely in a "type" section) and use that specialization in each other unit.
This is by design and the case in Delphi as well.

Regards,
Sven

Maciej Izak

2013-08-12 20:40

reporter   ~0069352

Last edited: 2013-08-12 20:48

View 2 revisions

Hi, but A.TFoo<Integer> and B.TFoo<Integer> is the same type, so class constructor should be executed once (checked in Delphi). Class variables should be shared between this two specializations... For A.TFoo<Integer>, B.TFoo<string>, B.TFoo<Integer>, B.TFoo<Byte> class constructor should be executed three times (and should be three "instances" of class variables).

I see some problem: hidden parameter Self. With normal class constructors there is no sense for Self parameter in class constructor. With generic types hidden Self parameter have sense (self as class reference type like in no static class methods), for example this is the only way for automatic registration of each generic specialization in some kind of factory:

var
  Factory: TList<TClass>;

class constructor TFoo<T>.Create;
begin
  Factory.Add(Self);
end;

Regards,
HNB

Sven Barth

2013-08-13 10:55

manager   ~0069361

You are right that class constructors are executed only once. I'll need to check how I can implement that.
Class variables on the other hand are definitely *not* shared (just tested in Delphi XE). See attached example.

Regards,
Sven

Maciej Izak

2013-08-13 11:27

reporter   ~0069363

In the attached example dpr file is missing...

Sven Barth

2013-08-13 13:27

manager  

genclassconstr.zip (2,603 bytes)

Sven Barth

2013-08-13 13:27

manager   ~0069365

That happens if one let's Windows hide the file extension... -.-
I've reuploaded the archive.

Regards,
Sven

Maciej Izak

2013-08-13 15:05

reporter   ~0069367

Last edited: 2013-08-13 15:13

View 3 revisions

I have already done pieces of tests:

Delphi 2010 not shared (output 42 42 0)
Delphi XE not shared (output 42 42 0)
Delphi XE2 shared (output 42 21 84)
Delphi XE4 shared (output 42 21 84)

so in Delphi XE2 they fixed the problem

Regards,
HNB

Sven Barth

2013-08-13 19:53

manager   ~0069369

Hmpf... now I need to find out how to fix this -.-

Regards,
Sven

Thaddy de Koning

2014-01-25 18:28

reporter   ~0072671

Last edited: 2014-01-25 18:29

View 2 revisions

Not so fast...
WHICH Delphi compiler from XE2 onwards. The back-ends (32/64 and platforms) are different and are known to be rather unpredictable in their interpretation regarding each others compatibility. AFAIK the 32 bit compiler is still completely based on legacy code and the company is almost without proper compiler engineers. Plz always write if it is consistent over all the compilers in a certain suite.
Otherwise an delphi mode incompatibility gets fixed where it shouldn't.

Although in this case the reporter seems to be on the right track.

Maciej Izak

2014-01-25 18:36

reporter   ~0072672

@Thaddy de Koning: OK :). Check out new dedicated report http://bugs.freepascal.org/view.php?id=25599 . Output for XE2 is the same for 64bits and 32bits. This behavior is described in the documentation of Delphi ( http://docwiki.embarcadero.com/RADStudio/XE5/en/Methods#Class_Constructors ). At the time XE2 Barry Kelly still worked at the Embarcadero :)

Sven Barth

2015-01-06 13:52

manager   ~0080151

That documentation is not really helping... for specialized class constructors they say that they might run multiple times even for the same specialization, but yet class variables seem to behave differently... *sigh*

Regards,
Sven

Maciej Izak

2015-01-06 18:21

reporter   ~0080158

"class variables" combined with "class constructors" are useless in D2010 and XE. Only XE2 and newer implementation is correctly: one class constructor call and one class variable instance per specialization.

Very important for Generics.* namespace 0027206 :

generics.dictionariesh.inc (line: 356)
generics.defaults.pas (line: 975, 989, 1017)

Regards,
Maciej Izak

Sven Barth

2015-01-06 20:06

manager   ~0080160

Their *documentation* states differently. And that's what annoys me as hell! They have people who are *paid* for this and that should at least be able to avoid contradictions. -.-

Regards,
Sven

Maciej Izak

2015-10-26 15:58

reporter   ~0086879

Any progress?

Cyrax

2015-10-26 19:02

reporter   ~0086882

Last edited: 2015-10-26 19:25

View 2 revisions

Your example snippet seems to work with FPC trunk r32153. No error message is displayed when compiling it.

---

Lazarus revision 50168
FPC revision 32153
 
FPC make commands:
clean
all
install
OPT=-gw2 -godwarfsets -godwarfmethodclassprefix -gl -O- -Xs- -Si- -vbq -XX -CX -dTEST_WIN32_SEH
COMPILER_OPTIONS=-gw2 -godwarfsets -godwarfmethodclassprefix -gl -O- -Xs- -Si- -vbq -XX -CX -dTEST_WIN32_SEH
INSTALL_PREFIX=F:\free_pascal_and_lazarus\fpc\i386\trunk\binary\fpc_trunk
UPXPROG=echo
IDE=1
REVSTR=32153
ALLOW_WARNINGS=1
NOWPOCYCLE=1
 
Lazarus make commands:
clean
all
OPT=-gw2 -godwarfsets -godwarfmethodclassprefix -gl -gh -O- -OoNO -Xs- -Si- -vb -XX -CX -dTEST_WIN32_SEH -dHEAPTRC_WINDOW -dDBG_WITH_DEBUGGER_DEBUG
UPXPROG=echo
USESVN2REVISIONINC=0

--

EDIT : Ahh, sorry it was already fixed! :)

Maciej Izak

2015-10-26 20:01

reporter   ~0086884

IMO dedicated report 0028911 is better than comments about class var here :)

Sven Barth

2015-10-30 14:09

manager   ~0087025

Okay, I'm resolving this now since the specific problem is fixed in trunk for quite some time already and the part about the behaviour of class vars is in 0028911.

Regards,
Sven

Issue History

Date Modified Username Field Change
2013-08-09 15:27 Maciej Izak New Issue
2013-08-09 15:27 Maciej Izak File Added: project18.lpr
2013-08-09 15:29 Maciej Izak Tag Attached: generics
2013-08-11 13:24 Sven Barth Fixed in Revision => 25234
2013-08-11 13:24 Sven Barth Note Added: 0069334
2013-08-11 13:24 Sven Barth Status new => resolved
2013-08-11 13:24 Sven Barth Fixed in Version => 2.7.1
2013-08-11 13:24 Sven Barth Resolution open => fixed
2013-08-11 13:24 Sven Barth Assigned To => Sven Barth
2013-08-12 20:40 Maciej Izak Note Added: 0069352
2013-08-12 20:40 Maciej Izak Status resolved => feedback
2013-08-12 20:40 Maciej Izak Resolution fixed => reopened
2013-08-12 20:48 Maciej Izak Note Edited: 0069352 View Revisions
2013-08-13 10:55 Sven Barth Note Added: 0069361
2013-08-13 10:55 Sven Barth File Added: genclassconstr.zip
2013-08-13 11:27 Maciej Izak Note Added: 0069363
2013-08-13 11:27 Maciej Izak Status feedback => assigned
2013-08-13 13:27 Sven Barth File Deleted: genclassconstr.zip
2013-08-13 13:27 Sven Barth File Added: genclassconstr.zip
2013-08-13 13:27 Sven Barth Note Added: 0069365
2013-08-13 15:05 Maciej Izak Note Added: 0069367
2013-08-13 15:07 Maciej Izak Note Edited: 0069367 View Revisions
2013-08-13 15:13 Maciej Izak Note Edited: 0069367 View Revisions
2013-08-13 19:53 Sven Barth Note Added: 0069369
2014-01-25 18:28 Thaddy de Koning Note Added: 0072671
2014-01-25 18:29 Thaddy de Koning Note Edited: 0072671 View Revisions
2014-01-25 18:36 Maciej Izak Note Added: 0072672
2014-02-13 21:10 Sven Barth Relationship added related to 0025599
2015-01-06 13:52 Sven Barth Note Added: 0080151
2015-01-06 13:52 Sven Barth Relationship added parent of 0027206
2015-01-06 13:56 Sven Barth Relationship deleted parent of 0027206
2015-01-06 13:56 Sven Barth Relationship added related to 0027206
2015-01-06 18:21 Maciej Izak Note Added: 0080158
2015-01-06 20:06 Sven Barth Note Added: 0080160
2015-10-26 15:58 Maciej Izak Note Added: 0086879
2015-10-26 19:02 Cyrax Note Added: 0086882
2015-10-26 19:25 Cyrax Note Edited: 0086882 View Revisions
2015-10-26 20:01 Maciej Izak Note Added: 0086884
2015-10-30 14:08 Sven Barth Relationship added related to 0028911
2015-10-30 14:09 Sven Barth Note Added: 0087025
2015-10-30 14:09 Sven Barth Status assigned => resolved
2015-10-30 14:09 Sven Barth Resolution reopened => fixed