1

I am implementing some dynamic input validator in Dart. See code:

abstract class Validator<T> {
  void validate(T value);
  
  static Validator<T> create<T>(String validatorType) {
    if (validatorType == 'name') {
      return NameValidator<T>();
    }
    if (validatorType == 'range') {
      // How to write:  assert(T is Comparable)
      return RangeValidator<T>(); //  error: 'T' doesn't extend 'Comparable<dynamic>'.
    }
    return null;
  }
}

class NameValidator<T> extends Validator<T> {
  @override
  void validate(T value) {
    assert(value.toString() == "foo");
  }
}

class RangeValidator<T extends Comparable> extends Validator<T> {
  @override
  void validate(T value) {
    assert(value.compareTo(42) < 0);
  }
}

The static function of the base class Validator.create() will create an instance of subclass based on the given validatorType. The generic paramater T in subclass RangeValidator class needs to be comparable, but it is not a requirement in base class Validator and subclass NameValidator.

I have two questions:

  1. How to write code the validate the generic type T extends Comparable?
  2. How to cast type T to Comparable to instantiate the subclass RangeValidator?

Thanks.

Yun Huang
  • 4,256
  • 7
  • 27
  • 36
  • 1
    Not possible since this would not be possible to analyze when compiling. Generics must be able to be determined by the analyzer but since `create`'s behavior is controlled by an argument, which can be set at runtime, the analyzer cannot predict the type of the returned value or predict what type would be valid as `T`. Instead of the `validatorType` argument, you should create multiple methods like `createNameValidator` where you can then define the type requirement for `T`. – julemand101 Jan 13 '21 at 09:37

1 Answers1

1

It's not possible.

You can check whether T is a subtype of Comparable in a number of ways. The easiest is probably a helper function like:

bool isSubtype<Sub, Super>() => <Sub>[] is List<Super>;

That won't help you with the other half of the problem, though.

There is no way in Dart to "promote" a type variable to have a bound that it didn't originally have. The language can promote a value of type T to have a magical intersection type T & Comparable, say by doing T x = ...; if (x is Comparable) { ... x is "T&Comparable" here ...}, but it can't use that for anything expect calling Comparable members on the value. It doesn't affect the type T (because T might not be a subtype of Comparable just because the value is).

And there is no promoting type variables.

So, you can do 1, but you cannot do 2.

lrn
  • 64,680
  • 7
  • 105
  • 121
  • Thanks. For question 2, I end up with casting the value of type T to Comparable. Something like `assert((value1 as Comparable).compareTo(value2))`. – Yun Huang Jan 14 '21 at 05:14