Dart generics method not recognizing type - flutter

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.

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.

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;
}
}

Related

Dart - Way to access a inherited static property from a parent class method

In PHP there is a way of accessing a static property value that is defined/overridden on an inheritor.
e.g.
class Foo {
public static $name='Foo';
public function who(){
echo static::$name;//the static operator
}
}
class Bar extends Foo {
public static $name='Bar';
}
$bar = new Bar();
$bar->who();
//Prints "Bar";
Is there ANY way of doing the exact same thing in Dart language?
Addressing comments:
About making it instance prop/method: There's a reason for the existence of static properties and methods and it's not having to create a new instance of the object to access a value or functionality that is not mutable.
Yes, but that's not how you are using it. Your use case is to invoke the method on an object, and therefore you really want an instance method. Now, some languages automatically allow invoking class methods as instance methods, and I see two choices for a language that offers that ability:
Statically transform fooInstance.classMethod() to ClassFoo.classMethod() based on the declared type (not the runtime type) of the object. This is what Java and C++ do.
Implicitly generate virtual instance methods that call the class method. This would allow fooInstance.classMethod() to invoke the appropriate method based on the runtime type of the object. For example, given:
class Foo {
static void f() => print('Foo.f');
}
You instead could write:
class Foo {
static void classMethod() => print('Foo.f');
final instanceMethod = classMethod;
}
and then you either could call Foo.classMethod() or Foo().instanceMethod() and do the same thing.
In either case, it's syntactic sugar and therefore isn't anything that you couldn't do yourself by being more verbose.
About the "meaning of static" and "only work because they allow invoking class methods as instance methods" : That affirmation is actually wrong. In the case of PHP, as per the example above, the Language is providing a way to access the TYPE of the class calling the method in the inheritance chain. A(methodA) >B > C. When C calls methodA, PHP allows you to know that the class type you're in is indeed C, but there's no object instance attached to it. the word "static" there is a replacement for the caller class type itself
All of that is still known at compilation time. That C derives from B derives from A is statically known, so when you try to invoke C.methodA, the compiler knows that it needs to look for methodA in B and then in A. There's no dynamic dispatch that occurs at runtime; that is still compile-time syntactic sugar. That is, if you wanted, you could explicitly write:
class A {
static void methodA() {}
}
class B extends A {
static void methodA() => A.methodA();
}
class C extends B {
static void methodA() => B.methodA();
}
Anyway, in your example, you could write:
class Foo {
static String name = 'Foo';
String get nameFromInstance => name;
void who() {
print(nameFromInstance);
}
}
class Bar extends Foo {
static String name = 'Bar';
#override
String get nameFromInstance => name;
}
void main() {
var bar = Bar();
bar.who(); // Prints: Bar
}

how to get the extender or implementer child's Type

I have a class:
abstract class Foo {
String getName(T f);
}
and:
class Bar implements Foo {}
or
class Bar extends Foo {}
how can Foo know Bar and implement T as Bar?
UPDATE:
I considered statically passing the type of the child, like:
#override
String getName<Bar>(Bar p1) {
return p1.name;
}
this way I ran into this error: The property 'name' can't be unconditionally accessed because the receiver can be 'null'. Try making the access conditional (using '?.') or adding a null check to the target ('!').
so, I edited it to be:
#override
String getName<Bar>(Bar p1) {
return p1!.name;
}
and now I'm getting this error: The getter 'name' isn't defined for the type 'Bar & Object'. Try importing the library that defines 'name', correcting the name to the name of an existing getter, or defining a getter or field named 'name'.
I guess the only solution, for now, is using dynamic type, like this:
abstract class Foo {
String getName(f);
}
and
class Bar implements Foo {
#override
String getName(f) {
return (f as Bar).name;
}
}
but I'd really like to know the answer to this question.
abstract class Foo {
String getName(T f);
}
should not be valid. T is not specified anywhere.
You need to specify a place for the generic to be passed:
abstract class Foo<T> {
String getName(T f);
}
Then pass that generic when you extend/implement the abstract class:
abstract class Foo<T> {
String getName(T f);
}
class Bar implements Foo<Bar> {
final String name = '';
#override
String getName(Bar p1) {
return p1.name;
}
}
If getName will always accept an implementer of Foo, you can remove the generic and instead use the covariant keyword:
abstract class Foo {
String getName(covariant Foo f);
}
class Bar implements Foo {
final String name = '';
#override
String getName(Bar p1) {
return p1.name;
}
}

void Function(Subype) isn't a valid override of void Function(ParentType)

I'm trying to create a parent type (IDataProvider) and a subtype (ILocalDataProvider), and then in a class, specify the subtype to take the place of the parent type. Here is what I mean:
abstract class IDataProvider {
ValueType get<ValueType>(String keyToRead);
}
abstract class ILocalDataProvider extends IDataProvider {
bool isKeyExistent(String key);
}
abstract class IDataSource {
IDataProvider dataProvider;
}
class LocalDataSource implements IDataSource {
LocalDataSource({#required this.dataProvider});
#override
ILocalDataProvider dataProvider; //*************** ERROR ON THIS LINE **********//
}
I'm getting this error:
'LocalDataSource.dataProvider=' ('void Function(ILocalDataProvider)')
isn't a valid override of 'IDataSource.dataProvider=' ('void
Function(IDataProvider)').
I thought that since ILocalDataProvider is a subtype of IDataProvider, it will be recognised as an IDataProvider?? What am I doing wrong?
You can't do that. The functions' signatures must match exactly. However, you can use a generic parameter like this: abstract class IDataSource<ProviderType extends IDataProvider> {}

Dart/vscode: enforce function argument types when passing function itself as an argument to constructor

As the subject suggests, how does one enforce function argument types in editor (say VSCode) when the function itself is passed as an argument to a class constructor? This goes for complex types. In the simple example below, vscode linter doesn't hiccup when calling the passed add() function with incorrect (int) argument rather than the correct (String) argument:
class ChildClass {
final Function add;
ChildClass(this.add);
...
add('this is a string'); <---- HOW TO ENFORCE STRING ARGUMENT TYPE?
add(5); <----- EDITOR (VSCODE) should hiccup currently doesn't
}
class ParentClass {
int _add(String text) { <--- ARGUMENT OF TYPE STRING
// some code
}
final childClass = ChildClass(_add); <-- pass add() as argument to ChildClass ctor
}
Not sure if this is a vscode linter question or a dart question or both. Thoughts much appreciated.
You can specify function types inline
class ChildClass {
final int Function(String text) add;
or as typedef
typedef AddFn = int Function(string text);
class ChildClass {
final AddFn add;
See also
https://github.com/dart-lang/sdk/blob/master/docs/language/informal/generic-function-type-alias.md
https://www.dartlang.org/guides/language/language-tour#typedefs

Typescript access static attribute of generic type

I have an abstract class Model with a static attribute and another generic class Controller<T extends Model>. I want to access the static attribute of Model in an instance of Controller. That should like this:
abstract class Model{
static hasStatus: boolean = false;
}
class MyModel extends Model{
static hasStatus = true;
}
class Controller<T extends Model>{
constructor(){
if(T.hasStatus)...
}
}
But TS says 'T' only refers to a type, but is being used as a value here.
Is there an easy way to achieve this? Or should i subclass Controller for each Heritage of Model and implement a method to retrieve the value?
There is no way to do that in typescript. Generic type parameters can only appear where types may appear in declarations, they are not accessible at runtime. The reason for that is simple - single javascript function is generated for each method of the generic class, and there is no way for that function to know which actual type was passed as generic type parameter.
If you need that information at runtime, you have to add a parameter to the constructor and pass a type yourself when calling it:
class Controller<T extends Model>{
constructor(cls: typeof Model){
if (cls.hasStatus) {
}
}
}
let c = new Controller<MyModel>(MyModel);
Here is how it looks when compiled to javascript to illustrate the point - there is nothing left of generic parameters there, and if you remove cls parameter there is no information about where hasStatus should come from.
var Controller = (function () {
function Controller(cls) {
if (cls.hasStatus) {
}
}
return Controller;
}());
var c = new Controller(MyModel);