> On Oct 6, 2019, at 5:40 PM, Mattias Gaertner via fpc-pascal 
> <fpc-pascal@lists.freepascal.org> wrote:
> 
>> Which test? Please post a sample.
> 
> generic procedure DoThis<T>(a:T; b:T);
> begin end;
> 
> begin
>  DoThis(1,200); // 1 sets T to shortint, so the 200 gives a warning
> end;
> 

What is the preferred behavior? I’m getting an error in ObjFPC mode.

{$mode objfpc}
{$modeswitch implicitfunctionspecialization}

program timpfuncspez16;

generic procedure DoThis<T>(param1: T; param2: T);
begin
end;

begin
  DoThis(1, 200);
end.

> 
>>> 3.
>>> timpfuncspez2.pp
>>> DoThis<T>
>>> DoThis<T,U>
>>> Delphi gives an error "Ambiguous call to DoThis". FPC silently
>>> selects the one with only one param. IMO this is dangerous, it
>>> should give an error.  
> 
> generic function DoThis<T>(a: T): T; overload;
> begin end;
> generic function DoThis<T,U>(a: T): U; overload;
> begin end;
> 
> begin
>  DoThis(3); // both fits, should give an error
> end;

This is debatable I think but I understand why "Ambiguous call to DoThis” would 
make sense. I’m pretty sure C# does this also.

What is the rule then? I’ll have to think about that some more.

> 
> 
>> [...]
>>> 4.
>>> Why does timpfuncspez6 fail?
>>> It works in Delphi.
>>> The comment has an explanation, which looks wrong to me:
>>> 
>>> generic procedure DoThis<T,U>(msg: T; param1: U; param2: TObject);
>>> begin
>>> end;
>>> 
>>> begin
>>>       DoThis('aa', 'aa', TObject.Create);
>>>       // wil be specialized as DoThis(msg: integer; param1:
>>> TObject; param2: TObject)
>>>       // so we expect an incompatible type error
>>>       DoThis(1, 1, TObject.Create);
>>> end.  
>> 
>> That doesn’t make sense to me either so I need to study it. Both
>> should fail actually as I designed it (for now).
> 
> Why?

I think my logic is different from what you expect though and I’m happy to 
change it if we need to.

There’s the comment I left in the code for the “try_implicit_specialization” 
function.

{         find generic procsyms by param count, starting from
          number of parsed params. if a procsym is found then
          validate via tcallcandidates and build list of *unique*
          types for use when specializing.
        
          inferred generic types are evaluated by inserting
          non-repating types into the list in linear order.
            (1,'string') = <Integer,String>
            (1,2,3,4,5,6) = <Integer>
            ('a','b') = <String>
            ('string',1) = <String,Integer>
            ('a',1,'b',2,'c') = <String,Integer>
}


I think for this example my logic does: T = integer, U = TObject because the 
first 2 integers params are repeating so they both consume the single T and 
then the TObject consumes the U. That means the second param “1” is being 
passed for a TObject type. 

generic procedure DoThis<T,U>(msg: T; param1: U; param2: TObject);

DoThis(1, 1, TObject.Create); // DoThis(msg: integer; param1: TObject; param2: 
TObject);

I used this logic because it works for repeating patterns but it’s not very 
intuitive in cases where the arguments are the same number as the generic 
parameters.

What should be the rule here?

> 
> 
>> How does Delphi implicitly specialize this?
> 
> DoThis(1,1,nil); // T and U become shortint
> DoThis('aa','aa',nil); // T and U become string

So Delphi seems to match by index so param 1 = generic param 1. With repeating 
patterns this breaks downs but maybe it’s a special case if the function 
parameter count matches the generic parameter count?

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

Reply via email to