1

I have an abstract base class validator with a method which takes a generic type as parameter. I will be passing generic type parameter to base class from the subclass inheriting the base class.

Base Class:

abstract class BaseValidator {
   bool isValid<T>(T obj);
}

Child Class:

class IPv4Validator extends BaseValidator{

  final IPV4_REGEX = "^((25[0-5]|(2[0-4]|1d|[1-9]|)d).?\b){4}\$";

  @override
  bool isValid<String>(String obj) {
    bool hasMatch = RegExp(IPV4_REGEX).hasMatch(obj);
    return hasMatch;
  }

}

Here hasMatch takes in non nullable string. When I directly pass some string hasMatch doesn't throw an error. But when I try to pass the generic value in the method parameter, it shows an error.

The argument type 'String' can't be assigned to the parameter type 'String'.

I couldn't able to understand why generic type is not accepting, even though its compile-time type.

enter image description here

Gowtham K K
  • 3,123
  • 1
  • 11
  • 29
  • try to give a type to your regex: `final String IPV4_REGEX = "...";` – john Nov 19 '22 at 06:44
  • That won't solve this as I don't have a problem with `IPV4_REGEX` string. The problem is with `obj` String which is a generic type. – Gowtham K K Nov 19 '22 at 06:50
  • 1
    `isValid(String obj)` defines a generic method named `isValid` whose type parameter happens to be named `String`. It is identical to `isValid(T obj)` but with a more misleading name for its type parameter (and that's why you get a confusing error message about `String` not being assignable to `String`). It is *not* defining a method named `isValid` that accepts only `String` arguments. – jamesdlin Nov 19 '22 at 07:05
  • Hi @jamesdlin . Thanks for your answer. Your comment gave me quite an idea. But little confusing. Kasymebek answer solved mine. But I was wondering why type parameter works in classes and not for methods. As far as I know, both are type parameter are only compile type. Then why there is difference between type parameters in class and method. I would be helpful if you could able to provide extended answer about difference between my implementation and the accepted answer. – Gowtham K K Nov 19 '22 at 18:24
  • 1
    @GowthamKK I'm not sure what you mean. You can have both generic classes and methods. As I stated, `isValid(String obj)` doesn't do what you want because it declares a generic method, not a specialization of an existing generic method. This would be no different than if you declared a generic class with `class SomeGeneric`: in that case, `String` is not the `String` class, it is the arbitrary name of the generic type parameter. – jamesdlin Nov 19 '22 at 19:00

2 Answers2

2

The following code solves this particular problem. But it may be different from what you intended to implement. On the other hand, the code will be cleaner if you create a new concrete class for different data types.

abstract class BaseValidator<T> {
  bool isValid(T obj);
}

class IPv4Validator extends BaseValidator<String>{
  final IPV4_REGEX = "^((25[0-5]|(2[0-4]|1d|[1-9]|)d).?\b){4}\$";

  @override
  bool isValid(String obj) {
    bool hasMatch = RegExp(IPV4_REGEX).hasMatch(obj);

    return hasMatch;
  }
}

Explanation.
In the line class IPv4Validator extends BaseValidator<String> we are not declaring a new class BaseValidator, it is already declared as BaseValidator<T>. Here we are inheriting the specialization of the existing generic class BaseValidator. While in the line bool isValid<String>(String obj), we declare a new function, so the compiler understands it as if we were declaring a new generic function with a parameter type named String. So, here bool isValid<String>(String obj) is equivalent to bool isValid<T>(T obj), just instead of name T we used name String, which is not an object String.

Kasymbek R. Tashbaev
  • 1,154
  • 1
  • 4
  • 16
0

another fix that you can do is to use the covariant keyword, to implement that, try this:

abstract class BaseValidator<T> {
  bool isValid(T obj);
}

class IPv4Validator extends BaseValidator {
  final IPV4_REGEX = "^((25[0-5]|(2[0-4]|1d|[1-9]|)d).?\b){4}\$";

  @override
  bool isValid(covariant String obj) {
    bool hasMatch = RegExp(IPV4_REGEX).hasMatch(obj);
    return hasMatch;
  }
}
john
  • 1,438
  • 8
  • 18