[DART]: Telling dart generics that an attribute will exist when used - flutter

Not sure if I'm using generics properly but is there a way I can let <T> know that it has (or will have) a certain attribute when it's used? This wouldn't be a problem if it weren't generics but since it's not I keep getting the error The getter 'id' isn't defined for the type 'T & Object'.
class Foo<T> {
List<T> items = [];
removeById(int id) {
items.removeWhere((T element) => element.id! == id); // Error
}
}

You can have either static (compile-time) checks or runtime checks. For compile-time checks, you would need to parameterize your generic on some base interface. For example:
abstract class HasId {
int get id;
}
class MyClass implements HasId {
#override
final int id;
MyClass(this.id);
}
class Foo<T extends HasId> {
...
}
If you really want duck-typing, that inherently requires using dynamic to disable static type-checking and relying on runtime checks:
class Foo<T> {
List<T> items = [];
void removeById(int id) {
items.removeWhere((element) => (element as dynamic).id! == id);
}
}
If there's a possibility that instances of T might not have an id member, you will need to catch a potential NoSuchMethodError yourself.

Related

Dart generics method not recognizing type

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

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
}

Why can't print any statement outside the method body in class in dart

class Car {
var name;
var model;
var cc;
Car(this.name, this.model, this.cc);
printAll() {
print(name);
print(model);
print(cc);
}
print(name); //Showing Error
}
void main() {
var obj = Car("Marcedes", "Class E", 5000);
obj.printAll();
}
Why i can't do any kind of operation outside the method body. The code generates error in compilation which given bellow. The code write in Dartpad.
Error in Compilation. The output show
Error compiling to JavaScript:
main.dart:1:7:
Error: The non-abstract class 'Car' is missing implementations for these members:
You have declared a method named print with a parameter called name but without a method body, i.e. an abstract method. In order to instantiate a class, Dart obviously has to know what the method body is, therefore you cannot instantiate an abstract class.
You need to do two things:
Because you have an abstract method, and abstract methods are only allowed in abstract classes, you need to mark Car as abstract.
You need to create a subclass of Car that overrides print with an implementation, and then instead instantiate that class.
Something like this:
abstract class Car {
var name;
var model;
var cc;
Car(this.name, this.model, this.cc);
printAll() {
print(name);
print(model);
print(cc);
}
print(name); // Abstract method `print` with no implementation
}
class ConcreteCar extends Car {
ConcreteCar(name, model, cc): super(name, model, cc);
#override
print(name) {
// Implementation of `print`
}
}
void main() {
var obj = ConcreteCar("Mercedes", "Class E", 5000);
obj.printAll();
}
Note: I left the implementation of print empty because I didn't understand the reason for the abstract print method and what the goal of the design is. But it should be trivial for you to fill out the missing pieces.

Extending base List class with extra functionality in Dart language

This question is about Dart language.
I want to have a class which is just a List but with some extra functionality.
For example I have a class named Model:
class Model{
String name;
int type;
Model(this.name, this.type);
}
I know that Model's type could take only four values: from 0 to 3.
And I want to have a method, which can give me a List of Models of specified type, e.g. List<Model> modelCollection.getByType(int type);.
I plan to to have four 'hidden' Lists of the Models (grouped by type) in that class.
Thus I need to override addition and removal of List elements to make that hidden lists being up to date.
How can I realize this as easy as possible?
P.S. I know this is quite simple, but I'm poorly familiar with Object inheritance and can't find proper examples.
P.P.S. I've also checked this but don't know is it outdated or not and didn't catch the idea.
To make a class implement List there are several ways :
Extending ListBase and implementing length, operator[], operator[]= and length= :
import 'dart:collection';
class MyCustomList<E> extends ListBase<E> {
final List<E> l = [];
MyCustomList();
void set length(int newLength) { l.length = newLength; }
int get length => l.length;
E operator [](int index) => l[index];
void operator []=(int index, E value) { l[index] = value; }
// your custom methods
}
Mixin ListMixin and implementing length, operator[], operator[]= and length= :
import 'dart:collection';
class MyCustomList<E> extends Base with ListMixin<E> {
final List<E> l = [];
MyCustomList();
void set length(int newLength) { l.length = newLength; }
int get length => l.length;
E operator [](int index) => l[index];
void operator []=(int index, E value) { l[index] = value; }
// your custom methods
}
Delegating to an other List with DelegatingList from the quiver package:
import 'package:quiver/collection.dart';
class MyCustomList<E> extends DelegatingList<E> {
final List<E> _l = [];
List<E> get delegate => _l;
// your custom methods
}
Depending on your code each of those options have their advantages. If you wrap/delegate an existing list you should use the last option. Otherwise use one of the two first options depending on your type hierarchy (mixin allowing to extend an other Object).
A basic approach is to extend an Object with IterableMixin. It also seems that you don't even need to override the "length" getter or let's say all methods that the IterableMixin already provides.
import 'dart:collection';
class Model {
String name;
int type;
Model(this.name, this.type) {
}
}
class ModelCollection extends Object with IterableMixin {
List<Model> _models;
Iterator get iterator => _models.iterator;
ModelCollection() {
this._models = new List<Model>();
}
//get one or the first type
Model elementByType(int type) {
for (Model model in _models) {
if (model.type == type) {
return model;
}
}
}
//get all of the same type
List<Model> elementsByType(int type) {
List<Model> newModel = new List<Model>();
for (Model model in _models) {
if (model.type == type) {
newModel.add(model);
}
}
return newModel;
}
add(Model model) {
this._models.add(model);
}
}
Excuse my strong static typing.
You might be interested in quiver.dart's Multimap. It behaves like a Map that allows multiple values per key.
Here's the code on github: https://github.com/google/quiver-dart/blob/master/lib/src/collection/multimap.dart#L20
It's on pub simply as quiver. We'll be hosting the dartdocs somewhere soon.

autofac: IEnumerable<Lazy<IFoo, IFooMetaData>> --> Lazy.Value(with runtime param)?

Using Autofac, I have multiple IFoo components that take a run-time parameter in the constructor. I'm using some Metadata from the types along with the run-time parameter to construct and manage running instances.
interface IFoo
{
int RunTimeId { get; }
}
[FooMeta("ShaqFoo")]
class Foo1 : IFoo
{
public Foo1 (int runtTimeId)
{
...
}
[FooMeta("KungFoo")]
class Foo2 : IFoo
{
public Foo2 (int runtTimeId)
{
...
}
Module/Registration something like:
builder.Register<Func<int, Foo1>>(c =>
{
var cc = c.Resolve<IComponentContext>();
return id => cc.Resolve<Foo1>(TypedParameter.From<int>(id));
})
.As<Func<int, IFoo>>()
.WithMetadata<IFooMetaData>(m => m.For(sm => sm.FooType, typeof(Foo1)));
builder.Register<Func<int, Foo2>>(c =>
{
var cc = c.Resolve<IComponentContext>();
return id => cc.Resolve<Foo2>(TypedParameter.From<int>(id));
})
.As<Func<int, IFoo>>()
.WithMetadata<IFooMetaData>(m => m.For(sm => sm.FooType, typeof(Foo2)));
And a component that creates new Foos with the run-time parameters and metadata. I need to be create ALL IFoos for a given run-time parameter, and need to check for existing instances (essentially using Metadata + RunTimeId as a key) before creating.
public class FooActivator
{
public FooActivator(IEnumerable<Lazy<Func<int, IFoo>, IFooMetaData>> fooFactories)
{
m_FooFactories = fooFactories;
}
private void HandleNewRunTimeIdEvent(int id)
{
CreateFoosForNewId(id);
}
private void CreateFoosForNewId(int id)
{
foreach (var fooFactory in m_FooFactories)
{
if (!FooWithThisMetadataAndIdExists(fooFactory.Metadata.FooType, id))
{
var newFoo = fooFactory.Value(id);
}
}
}
}
Obviously, I can enumerate all of the IFoos and check metadata using the Lazy Enumeration, but can't pass in the run-time parameter to Lazy.Value. Seems like I need to pass in an Enumerable of Func<>s somehow, but can't figure out how to attach the metadata. Or maybe I need an entirely different approach?
Just getting my head wrapped around autofac, and hoping there's a clean way to accomplish this. I could settle for just using the concrete Foo type (instead of metadata) if there's a simple way to enumerate all of them (without creating them), and use the type + run-time Id as my key instead.
Updated the code with a working solution. Figured out how to register Factories properly with metadata. Seems to work.