generics question

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

generics question

Adrian Veith
Hi,

I try this:

type
  TTestGen<T> = class
    constructor Create();
    class function Test(val: T): string; inline;
  end;


function Blah(const val: Integer): string; inline; overload;
begin
  Result:= IntToStr(val + 1);
end;

function Blah(const val: string): string; inline; overload;
begin
  Result:= val + '1';
end;

{ TTestGen }

constructor TTestGen<T>.Create();
begin
end;

class function TTestGen<T>.Test(val: T): string;
begin
  Result:= Blah(val);
end;


type
  TTestInt = TTestGen<Integer>;
  TTestString = TTestGen<String>;    

and get an error: can't determin which overloaded function Blah to use.

It would be nice if this could work. It would be a way to inject inline
functions into a generic class - avoiding virtual functions.

BTW. If I only have one Blah and only one corresponding specialization
it works.

Cheers,

Adrian.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: generics question

leledumbo
Administrator
Err... because at the time, T is not yet known. It would still fail to compile even if you don't do any specialization. I guess the compiler does type checking while parsing the generic class (and its methods) declaration, not while specializing (well... it would still do type checking when specializing, but the error would be a little cryptic due to missing exact error location).

IMHO a solution would be to have additional compile-time syntax to check the type of T (but this may cause a lot of headache due to inheritance concept). Since it's impossible with the current state, the current solution would be to declare a procedural type (with T as argument) inside the generic class and instead of calling blah directly make it a procedural variable of that type as argument of Test (since it's a class function). The caveat is of course you have to pass Blah all the time. But unfortunately... it doesn't work as well :(

Here's your modified program (compiled, but just run and see its output):

{$mode delphi}

uses
  SysUtils;


function Blah(const val: Integer): string; inline; overload;
begin
  Result:= IntToStr(val + 1);
end;

function Blah(const val: string): string; inline; overload;
begin
  Result:= val + '1';
end;

type
  TTestGen<T> = class
  type
    TBlah = function (const val: T): string;
  public
    constructor Create();
    class function Test(val: T; ABlah: TBlah): string; inline;
  end;

{ TTestGen }

constructor TTestGen<T>.Create();
begin
end;

class function TTestGen<T>.Test(val: T; ABlah: TBlah): string;
begin
  Result:= ABlah(val);
end;


type
  TTestInt = TTestGen<Integer>;
  TTestString = TTestGen<String>;

begin
  WriteLn(TTestInt.Test(1,@Blah));
  WriteLn(TTestString.Test('test',@Blah));
end.

If I don't overload Blah and pass the correct function for each call, then the result is correct. Somebody's gotta file a bug report.
Reply | Threaded
Open this post in threaded view
|

Re: generics question

Adrian Veith
But is very strange, that this works:

type
  TTestGen<T> = class
    constructor Create();
    class function Test(val: T): string; inline;
  end;


function Blah(const val: Integer): string; inline; //overload;
begin
  Result:= IntToStr(val + 1);
end;

{function Blah(const val: string): string; inline; overload;
begin
  Result:= val + '1';
end;
}

{ TTestGen }

constructor TTestGen<T>.Create();
begin
end;

class function TTestGen<T>.Test(val: T): string;
begin
  Result:= Blah(val);
end;

type
  TTestInt = TTestGen<Integer>;
  //TTestString = TTestGen<String>;

begin
  writeln(TTestInt.Test(2));
  //writeln(TTestString.Test('2'));
  readln;
end.

T is also not yet known. Why does it not work with overloaded functions
? IMHO this is not consequent.

Cheers,

Adrian.

On 14.05.2011 11:09, leledumbo wrote:

> Err... because at the time, T is not yet known. It would still fail to
> compile even if you don't do any specialization. I guess the compiler does
> type checking while parsing the generic class (and its methods) declaration,
> not while specializing (well... it would still do type checking when
> specializing, but the error would be a little cryptic due to missing exact
> error location).
>
> IMHO a solution would be to have additional compile-time syntax to check the
> type of T (but this may cause a lot of headache due to inheritance concept).
> Since it's impossible with the current state, the current solution would be
> to declare a procedural type (with T as argument) inside the generic class
> and instead of calling blah directly make it a procedural variable of that
> type as argument of Test (since it's a class function). The caveat is of
> course you have to pass Blah all the time. But unfortunately... it doesn't
> work as well :(
>
> Here's your modified program (compiled, but just run and see its output):
>
> {$mode delphi}
>
> uses
>   SysUtils;
>
>
> function Blah(const val: Integer): string; inline; overload;
> begin
>   Result:= IntToStr(val + 1);
> end;
>
> function Blah(const val: string): string; inline; overload;
> begin
>   Result:= val + '1';
> end;
>
> type
>   TTestGen<T> = class
>   type
>     TBlah = function (const val: T): string;
>   public
>     constructor Create();
>     class function Test(val: T; ABlah: TBlah): string; inline;
>   end;
>
> { TTestGen }
>
> constructor TTestGen<T>.Create();
> begin
> end;
>
> class function TTestGen<T>.Test(val: T; ABlah: TBlah): string;
> begin
>   Result:= ABlah(val);
> end;
>
>
> type
>   TTestInt = TTestGen<Integer>;
>   TTestString = TTestGen<String>;
>
> begin
>   WriteLn(TTestInt.Test(1,@Blah));
>   WriteLn(TTestString.Test('test',@Blah));
> end.
>
> If I don't overload Blah and pass the correct function for each call, then
> the result is correct. Somebody's gotta file a bug report.
>
> --
> View this message in context: http://free-pascal-general.1045716.n5.nabble.com/generics-question-tp4389896p4395332.html
> Sent from the Free Pascal - General mailing list archive at Nabble.com.
> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> http://lists.freepascal.org/mailman/listinfo/fpc-pascal
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: generics question

Sven Barth-2
In reply to this post by Adrian Veith
I have not yet looked at the parsing of methods of generic classes
during my work on the generics, but when I'll implement generic methods
I'll try to take a look at your problem.

Regards,
Sven


On 12.05.2011 12:37, Adrian Veith wrote:

> Hi,
>
> I try this:
>
> type
>    TTestGen<T>  = class
>      constructor Create();
>      class function Test(val: T): string; inline;
>    end;
>
>
> function Blah(const val: Integer): string; inline; overload;
> begin
>    Result:= IntToStr(val + 1);
> end;
>
> function Blah(const val: string): string; inline; overload;
> begin
>    Result:= val + '1';
> end;
>
> { TTestGen }
>
> constructor TTestGen<T>.Create();
> begin
> end;
>
> class function TTestGen<T>.Test(val: T): string;
> begin
>    Result:= Blah(val);
> end;
>
>
> type
>    TTestInt = TTestGen<Integer>;
>    TTestString = TTestGen<String>;
>
> and get an error: can't determin which overloaded function Blah to use.
>
> It would be nice if this could work. It would be a way to inject inline
> functions into a generic class - avoiding virtual functions.
>
> BTW. If I only have one Blah and only one corresponding specialization
> it works.


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: generics question

leledumbo
Administrator
In reply to this post by Adrian Veith
My guess is that because there's only one Blah, it would be OK. Now try specializing TTestGen with String.