Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using own class as a type parameter constraint in class declaration

I have the following declaration of a class in Delphi XE8:

TestClass = class;
TestClass = class
  function test<T: TestClass>(supplier: TFunc<T>): T; // Compiler error
end;

Which throws the following compiler error:

E2086 Type 'TestClass' is not yet completely defined

When I add another class to the mix and use that one as constraint instead, it works fine:

AnotherTestClass = class
end;

TestClass = class;
TestClass = class
  function test<T: AnotherTestClass>(supplier: TFunc<T>): T; // No Error
end;

I suspect the problem is that the forward type declaration does not tell Delphi enough about the TestClass type yet. This is perhaps more obvious since the following attempt to work around the problem throws the very same compiler error on a different line:

TestClass = class;
AnotherTestClass = class (TestClass) // Compiler Error
end;
TestClass = class
  function test<T: AnotherTestClass>(supplier: TFunc<T>): T;
end;

Am I doing something wrong and if not, is there a way around this problem?

like image 580
overactor Avatar asked Jan 05 '16 11:01

overactor


1 Answers

You are not doing anything wrong. What you are attempting should be possible, but the compiler is, in my view, defective. There's no viable way to work around this without completely changing the design. One way to work around the issue would be to enforce the constraint at runtime. However, that would count, in my eyes, as completely changing the design.

Note that in .net what you are trying to do is perfectly possible:

class MyClass
{
    private static T test<T>(Func<T> arg) where T : MyClass
    {
        return null;
    }
}

The Delphi generics feature was based on .net generics and I rather suspect that the problem you face is down to an oversight on the part of the Delphi developers.

You should submit a bug report / feature request.

Update 1

LU RD suggests a better workaround. Use a class helper:

type
  TestClass = class
  end;

  TestClassHelper = class helper for TestClass
    function test<T: TestClass>(supplier: TFunc<T>): T;
  end;

This will allow you to have the constraint tested at compile time. However, it does force you to define the method outside the function which is untidy, and it stops you using a class helper for any other purpose. So, you should still submit a bug report / feature request in my view.

Update 2

Bug report: RSP-13348

like image 86
David Heffernan Avatar answered Sep 30 '22 01:09

David Heffernan