7

I'm trying to write a generic function that accepts matching parameter types.
Delphi does infer the type parameter correctly in the simple case of plain arguments.

eg:

type
  TFoo = class
    function Pair<T>(e1, e2: T): TList<T>;
  end;

calling this with aFoo.Pair(1, 2); works perfectly fine, but when I change the parameter signature to a generic type

type
  TFoo = class
    function InsertInto<T>(aList: TList<T>; aVal: T): TList<T>;
  end;

and try to call it
aFoo.InsertInto(TList<String>.Create, 'bar');

then the compiler complains about it:
E2010 Incompatible types: 'Generics.Collections.TList<uTest.TFoo.InsertInto.T>' and 'Generics.Collections.TList<System.String>'

Is there any way I can write this (or a similar) method, so that the client doesnt have to specity the type parameter?
aFoo.InsertInto<String>(TList<String>.Create, 'bar');

6
  • I think the error message gives you a clue that type inference is not going to get the job done here. It's clearly a harder problem for the compiler's inference system than the simple example at the top of the Q. Commented Oct 2, 2012 at 16:06
  • try to make aVal:T first parameter, maybe that would make it easier to compiler, but chance is very very poor Commented Oct 2, 2012 at 16:20
  • replace "string" with "strign" and enjoy E2010 Incompatible types: 'System.Generics.Collections.TList<unitname.TFoo.Pair.T>' and 'Boolean' Commented Oct 2, 2012 at 16:27
  • 2
    replace 1st parameter with nil and you'd get E2532 Couldn't infer generic type argument from different argument types for method 'Pair' // and this is probably the correct error, anything else was bogus. I think you can open QC ticket about misleading error messages Commented Oct 2, 2012 at 16:28
  • 2
    But @Arioch, we don't know whether the messages from the second function are really misleading because we don't yet understand the compiler's issue. The "couldn't infer generic type" error from the first function is irrelevant. For the second function, the compiler has evidently already inferred the types (since it's not complaining that it couldn't infer them), so the problem is instead one of recognizing that the inferred type is the same as the explicitly specified one — that uTest.TFoo.InsertInto.T is equivalent to System.String — if that's indeed what T has been inferred to be. Commented Oct 2, 2012 at 16:55

1 Answer 1

5

My guess is that comes from the strongly typed nature of Delphi.
uTest.TFoo.InsertInto.T is equivalent to System.String but it's actually a different type.

Much like in this example where Int1 and Int2 are not of the same type:

var
  Int1: array[1..10] of Integer;
  Int2: array[1..10] of Integer;
      ...
  Int1 := Int2; // <== BOOM! E2008 Incompatible types (in XE2)

The actual problem is not with type inference but with the types not being compatible per the strict rules of Pascal/Delphi.

Sign up to request clarification or add additional context in comments.

6 Comments

That sounds very plausible. One minor nit-pick. What you are talking about is type identity and compatibility, rather than strong/weak type systems.
It could also be that the type of the string literal 'bar' is not System.String — at least not yet. the type of a string literal is rather fluid; the compiler assigns it whatever type it needs to have, at least when it knows what type it needs. Think about how the same string literal can be passed as UnicodeChar, PAnsiChar, WideString, or ShortString, all from the same text in the code. So it may be that uTest.TFoo.InsertInto.T actually represents a half-dozen different types, and the compiler is unable to choose the "best" one.
It also doesn't work with Integer literals, although that might have a similar reason (Byte vs. Integer vs. Cardinal).
@RobKennedy can you get around this with a pointer to type perhaps? I had similar problems in Delphi7 but that wasn't really generics(templates) and that was the usual solution.
I am against this idea. Reason one: "array of integer" - static or dynamic - are incompatible. But all TArray<Integer> are the same. And there is generic TList<T> so it would follow latter trait, not former one. Reason two: I'd be very glad to see type TFileName = type string; making isolated string subtype. I personally think that would be both useful and consistent with idea behind type X = type Y. But that is not how Delphi works with strings. Strings are always assign-compatible no matter what type declaration you did.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.