Home > Software engineering >  Generic paramater that itself is generic
Generic paramater that itself is generic

Time:09-27

I have a factory class that is generic over T extends SomeClass<A>. But the thing is that A isn't known at the class level but only at the method level. To make myself a bit clearer with some code:

class Factory<T extends SomeClass<A>> { // Don't know A here
  T<A> Function<A>(A arg) _constructor; // Function that produces my T's and is generic over A
  Factory(this._constructor);
  
  T<String> newString(String arg){      // A is only known here
    return _constructor(arg);
  }
  T<int> newInt(int arg){
    return _constructor(arg);
  }
}

This obviously isn't legal Dart code, but is something to that effect even possible with Dart's generics, or does it require code generation? I tried to use extension methods, but they don't solve the problem that _constructor has the return type T<A>. And I explicitly don't want to / can't use T constructor<A, T extends SomeClass<A>>(A args).

CodePudding user response:

That's not directly possible the way Dart currently works. Dart's generics are only first order, so you cannot pass what is essentially a function from type to type as a type argument. Only plain types can be type arguments.

What you have here is a generic factory class. The kind of object it creates is defined at the class level (for ease, let's just assume that SomeClass here is Iterable, so it's a collection factory class, and you can choose, e.g., List or Set or Queue as the kind of collection to create), and then the element type of those collections are chosen when you call the factory methods. That cannot work, because there is no type that the class can store in the class type argument which can allow that usage later.

I'd probably use separate classes and normal inheritance for this:

abstract class Factory {
  Iterable<T> Function<T>(T) _constructor;
  Factory(Iterable<T> Function<T>(T) constructor) 
      : _constructor = constructor;
  Iterable<String> newString(String arg) => _constructor<String>(arg);
  Iterable<int> newINt(int arg) => _constructor<int>(arg);
}
class ListFactory extends Factory {
  ListFactory(List<T> Function<T>(T) constructor) : super(constructor);
  List<String> newString(String arg) => 
      super.newString(arg) as List<String>;
  List<int> newInt(int arg) => 
      super.newInt(arg) as List<int>;
}
  •  Tags:  
  • dart
  • Related