Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2014-10

Generics: constructor restriction fail

5 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

silvioprog

Hello,

Following this article:

http://alex.ciobanu.org/?p=51

The compiler does not check the constructor restriction.

Try this test:

{$mode delphi}
  TTest = class
  private // hidding the constructor to cause a compiler error
    constructor Create;
  end;
  TGen<T: class, constructor> = class
  end;
constructor TTest.Create;
begin
end;
var  Gen: TGen<TTest>;
begin
  Gen := TGen<TTest>.Create;
end;

It compiles well in FPC (from trunk), but the same code in XE is:

"[dcc32 Error] Unit1.pas(36): E2513 Type parameter 'T' must have one public parameterless constructor named Create"

It is a bug in FPC or I need to enable some directive switch?

Thank you!

Silvio Clécio My public projects - github.com/silvioprog
Sven Barth
to silvioprog
silvioprog wrote 35 lines
Hello, Following this article: http://alex.ciobanu.org/?p=51 The compiler does not check the constructor restriction. Try this test: {$mode delphi} TTest = class private // hidding the constructor to cause a compiler error constructor Create; end; TGen<T: class, constructor> = class end; constructor TTest.Create; begin end; var Gen: TGen<TTest>; begin Gen := TGen<TTest>.Create; end; It compiles well in FPC (from trunk), but the same code in XE is: "[dcc32 Error] Unit1.pas(36): E2513 Type parameter 'T' must have one public parameterless constructor named Create" It is a bug in FPC or I need to enable some directive switch?

"constructor" restrictions are not enforced currently, because with the way FPC handles generics compared to Delphi they are a bit useless. Consider this:

=== code begin ===

type
   TTest = class
   strict private // just to keep it hidden in the same unit
     constructor Create;
   end;
var
   t: TTest;
begin
   t := TTest.Create;
end.

=== code end ===

The above code snippet will compile, because the compiler will use the next best constructor that it can find which is at least the constructor of TObject.

Next snippet:

=== code begin ===

type
   TGeneric<T> = class
     procedure Test;
   end;
procedure TGeneric<T>.Test;
begin
   Writeln(T.Bar);
end;
begin
end.

=== code end ===

This will correctly compile in FPC, but not in Delphi, because FPC handles quite some type checking at specialization time not at declaration time. So this will fail to specialize (at compile time) if T does not implement a class method called "Bar".

Now let's put these two concepts together and exchange "T.Bar" with "T.Create" (and change the "Writeln" to something else of course ;) ) and it will still compile as long as T provides a Create method. Now as long T is a class this will always be the case, because there is at least the TObject constructor.

That's why the "constructor" constraint is currently not handled in anyway. That said there'd still be a usecase for this to ensure that there is a default constructor in the class. Also it might be worthwhile to rethink the type checking in case of mode Delphi for generics... :/

Regards,
Sven

silvioprog
to Sven Barth
Sven Barth wrote 93 lines
On 31.10.2014 00:04, silvioprog wrote: > Hello, > > Following this article: > > http://alex.ciobanu.org/?p=51 > > The compiler does not check the constructor restriction. > > Try this test: > > {$mode delphi} > > TTest = class > private // hidding the constructor to cause a compiler error > constructor Create; > end; > > TGen<T: class, constructor> = class > end; > > constructor TTest.Create; > begin > end; > > var Gen: TGen<TTest>; > begin > Gen := TGen<TTest>.Create; > end; > > It compiles well in FPC (from trunk), but the same code in XE is: > > "[dcc32 Error] Unit1.pas(36): E2513 Type parameter 'T' must have one > public parameterless constructor named Create" > > It is a bug in FPC or I need to enable some directive switch? > "constructor" restrictions are not enforced currently, because with the way FPC handles generics compared to Delphi they are a bit useless. Consider this: === code begin === type TTest = class strict private // just to keep it hidden in the same unit constructor Create; end; var t: TTest; begin t := TTest.Create; end. === code end === The above code snippet will compile, because the compiler will use the next best constructor that it can find which is at least the constructor of TObject. Next snippet: === code begin === type TGeneric<T> = class procedure Test; end; procedure TGeneric<T>.Test; begin Writeln(T.Bar); end; begin end. === code end === This will correctly compile in FPC, but not in Delphi, because FPC handles quite some type checking at specialization time not at declaration time. So this will fail to specialize (at compile time) if T does not implement a class method called "Bar". Now let's put these two concepts together and exchange "T.Bar" with "T.Create" (and change the "Writeln" to something else of course ;) ) and it will still compile as long as T provides a Create method. Now as long T is a class this will always be the case, because there is at least the TObject constructor.

Indded. Thanks for the explanation brother. =)

Show quoted text 5 lines
That's why the "constructor" constraint is currently not handled in anyway. That said there'd still be a usecase for this to ensure that there is a default constructor in the class. Also it might be worthwhile to rethink the type checking in case of mode Delphi for generics... :/

It seems good to check it like Delphi em mode delphi, keeping the compatibility. =/

Silvio Clécio My public projects - github.com/silvioprog
Chriss Kalogeropoulos
to silvioprog

Hi all,

I am not sure about the constructor case but I consider the FPC implementation of generics much more powerful than Delphi's assuming that Sven's comment actually works as expected.
The fact that the method invocation is actually checked on specialization and not on declaration means that someone can call methods on the type parameter directly and not through some interface restriction which IMO is an ugly hack and cancels all possible optimizations for non virtual methods, since they much be called through the interface VMT. On Delphi XE5 I tried to use an interface constraint so that the compiler won't complaint about the methods and then I tried to call them through an object variable. This created a compiler internal error, even for class methods (declared in the interface but called directly from the type parameter). On FPC however it worked and IMO this is a good feature.

Thanks,
Chriss
Στις 11 Νοε 2014 10:54 μ.μ., ο χρήστης "silvioprog" έγραψε:

Show quoted text 117 lines
On Sat, Nov 1, 2014 at 9:04 AM, Sven Barth wrote: > On 31.10.2014 00:04, silvioprog wrote: > >> Hello, >> >> Following this article: >> >> http://alex.ciobanu.org/?p=51 >> >> The compiler does not check the constructor restriction. >> >> Try this test: >> >> {$mode delphi} >> >> TTest = class >> private // hidding the constructor to cause a compiler error >> constructor Create; >> end; >> >> TGen<T: class, constructor> = class >> end; >> >> constructor TTest.Create; >> begin >> end; >> >> var Gen: TGen<TTest>; >> begin >> Gen := TGen<TTest>.Create; >> end; >> >> It compiles well in FPC (from trunk), but the same code in XE is: >> >> "[dcc32 Error] Unit1.pas(36): E2513 Type parameter 'T' must have one >> public parameterless constructor named Create" >> >> It is a bug in FPC or I need to enable some directive switch? >> > > "constructor" restrictions are not enforced currently, because with the > way FPC handles generics compared to Delphi they are a bit useless. > Consider this: > > === code begin === > > type > TTest = class > strict private // just to keep it hidden in the same unit > constructor Create; > end; > > var > t: TTest; > begin > t := TTest.Create; > end. > > === code end === > > The above code snippet will compile, because the compiler will use the > next best constructor that it can find which is at least the constructor of > TObject. > > Next snippet: > > === code begin === > > type > TGeneric<T> = class > procedure Test; > end; > > procedure TGeneric<T>.Test; > begin > Writeln(T.Bar); > end; > > begin > end. > > === code end === > > This will correctly compile in FPC, but not in Delphi, because FPC > handles quite some type checking at specialization time not at declaration > time. So this will fail to specialize (at compile time) if T does not > implement a class method called "Bar". > > Now let's put these two concepts together and exchange "T.Bar" with > "T.Create" (and change the "Writeln" to something else of course ;) ) and > it will still compile as long as T provides a Create method. Now as long T > is a class this will always be the case, because there is at least the > TObject constructor. > Indded. Thanks for the explanation brother. =) > That's why the "constructor" constraint is currently not handled in > anyway. That said there'd still be a usecase for this to ensure that there > is a default constructor in the class. Also it might be worthwhile to > rethink the type checking in case of mode Delphi for generics... :/ > It seems good to check it like Delphi em mode delphi, keeping the compatibility. =/ -- Silvio Clécio My public projects - github.com/silvioprog _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
silvioprog
to Chriss Kalogeropoulos

On Tue, Nov 11, 2014 at 7:08 PM, Chriss Kalogeropoulos <

Show quoted text 18 lines
wrote: Hi all, I am not sure about the constructor case but I consider the FPC implementation of generics much more powerful than Delphi's assuming that Sven's comment actually works as expected. The fact that the method invocation is actually checked on specialization and not on declaration means that someone can call methods on the type parameter directly and not through some interface restriction which IMO is an ugly hack and cancels all possible optimizations for non virtual methods, since they much be called through the interface VMT. On Delphi XE5 I tried to use an interface constraint so that the compiler won't complaint about the methods and then I tried to call them through an object variable. This created a compiler internal error, even for class methods (declared in the interface but called directly from the type parameter). On FPC however it worked and IMO this is a good feature.

Recently I have installed Free Pascal 2.7.1 and I got very suprised about the new implementations in generic structures. I'm even thinking about rewriting some of my classes to reuse those resources to the fullest.

I'm excited about the Free Pascal 2.8. I want to teach an advanced course of Object Pascal here in Brazil, and the Free Pascal will be the leading actor at this story. =)

Silvio Clécio My public projects - github.com/silvioprog