Dart, never allow nested Generics? - dart

I would like to use the nested Generics, like
class Class<List<T>> {
...
}
But always Dart Editor gives me alerts. How should I avoid these alerts?

Well, Dart Editor is right. This code doesn't make any sense. Without further information on what you are trying to do (don't hesitate to update your question), I am assuming you actually mean one of those:
class MyClass<T> {
List<T> listField;
// other stuff
}
Or maybe the list itself should be generic?
void main() {
MyClass<SomeCustomListClass<String>> instance = new MyClass();
}
class MyClass<T extends List<String>> {
T listField;
// ...
}
Or maybe everything has to be generic:
void main() {
MyClass<String, SomeCustomListClass<String>> instance = new MyClass();
}
class MyClass<TElement, TList extends List<TElement>> {
TList listField;
TElement _firstListElement;
// whatever that could be used for
}

Related

Getting type of another generic type from Dart type parameter

I would like to make a generic class which only accepts Lists as a type parameter. But I also want the type parameter of the List. Something like this:
class MyClass<L extends List<T>> {
T foo() {
// ....
}
}
The problem is that that does not work. T is not found. But this does:
class MyClass<L extends List<T>, T> {
T foo() {
// ....
}
}
My only issue with this is that I have to always pass in the extra parameter T which should be inferred from the List type.
var instance = MyClass<List<int>>();
var instance = MyClass<List<int>, int>(); // Extra int kind of redundant
Is there any workaround to this?
The solution is similar to the one provided in this question (the same problem, but in Java): basically, you can't do that in Dart. What you can do is
create a new subclass:
class MyClass2<T> extends MyClass<List<T>, T> { ... }
or
create a factory method:
class MyClass<L extends List<T>, T> {
static MyClass<List<T>, T> fromList<T>(List<T> list) {
return MyClass(...);
}
}

Dart create class instance by string with class name

I want to invoke functions of a class by their names inside a string. I know my best option are Mirrors.
var ref = reflect(new TestClass());
ref.invoke(Symbol("test"), []);
It works fine, I can call the function test by a string. But I also want to put "TestClass" inside a string. Is it possible somehow ?
var ref = reflect("TestClass");
ref.invoke(Symbol("test"), []);
Jonas
You can do something like this:
import 'dart:mirrors';
class MyClass {
static void myMethod() {
print('Hello World');
}
}
void main() {
callStaticMethodOnClass('MyClass', 'myMethod'); // Hello World
}
void callStaticMethodOnClass(String className, String methodName) {
final classSymbol = Symbol(className);
final methodSymbol = Symbol(methodName);
(currentMirrorSystem().isolate.rootLibrary.declarations[classSymbol]
as ClassMirror)
.invoke(methodSymbol, <dynamic>[]);
}
Note, that this implementation does require that myMethod is static since we are never creating any object but only operate directly on the class itself. You can create new objects from the class by calling newInstance on the ClassMirror but you will then need to call the constructor.
But I hope this is enough. If not, please ask and I can try add some more examples.

How to specify a data type for a container class in Dart

I am looking for the dart syntax to achieve the following but do not know what the correct terminology is to search for the answer.
class BaseClass <T extends MyType> {
List<T> items;
T getFirstItem() => items.first;
}
and then be able to Sub class like this
class ClassForMyType<MyType> extends BaseClass {
List<MyType> items;
MyType getFirstItem() => items.first;
}
Where ClassForMyType would extend BaseClass so that I do not have to re-implement the contrived getFirstItem() method.
Effectively I want to be able to use it like this:
ClassForMyType container = ClassForMyType();
MyType item = Mytype();
container.items.add(item);
List<MyType> itemsFromContainer = container.items;
MyType firstItem = container.getFirstItem();
I have tried something like this:
BaseClass<T extends MyType> {
List<T> items;
void addItemFromMap(Map map) {
items.add(T.fromMap(map));
}
}
The above fails on the .fromMap() which does exist on MyType. In other methods where I access other methods on MyType these appear to work, it seems to have a problem only wiht the named contructor.
I think the only way that would work and look relatively OK would be:
abstract class BaseClass<T extends MyType> {
List<T> items;
// abstract factory method
T itemFromMap(Map map);
void addItemFromMap(Map map) {
items.add(itemFromMap(map));
}
}
class ClassForMyType extends BaseClass<MyType> {
// implementing abstract factory method, delegating call to constructor
MyType itemFromMap(Map map) => MyType.fromMap(map);
}
I agree, a little bit overhead that you should implement factory method in every subclass, but that is the only proper way.

Creating an interface for construction

A few times now I've run into a use case where I need to define an interface for how classes construct themselves. One such example could be if I want to make an Interface Class that defines the interface by which objects can serialize and unserialize themselves (for input into a database, to be sent as JSON, etc). You might write something like this:
abstract class Serializable {
String serialize();
Serializable unserialize(String serializedString);
}
But now you have a problem, as serialize() is properly an instance method, and unserialize() should instead be a static method (which isn't inheritable or enforced by the Interface) or a constructor (which also isn't inheritable).
This leaves a state where classes that impliment the Serializable interface are required to define a serialize() method, but there is no way to require those classes to define a static unserialize() method or Foo.fromSerializedString() constructor.
If you make unserialize() an instance method, then unserializing an implementing class Foo would look like:
Foo foo = new Foo();
foo = foo.unserialize(serializedString);
which is rather cumbersome and ugly.
The only other option I can think of is to add a comment in the Serializable interface asking nicely that implementing classes define the appropriate static method or constructor, but this is obviously prone to error if a developer misses it and also hurts code completion.
So, is there a better way to do this? Is there some pattern by which you can have an interface which forces implementing classes to define a way to construct themselves, or something that gives that general effect?
You will have to use instance methods if you want the inheritance guarantees. You can do a bit nicer than manual instantiation though, by using reflection.
abstract class Serializable {
static Serializable fromSerializedString(Type type, String serializedString) {
ClassMirror cm = reflectClass(type);
InstanceMirror im = cm.newInstance(const Symbol(''), []);
var obj = im.reflectee;
obj.unserialize(serializedString);
return obj;
}
String serialize();
void unserialize(String serializedString);
}
Now if someone implements Serializable they will be forced to provide an unserialize method:
class Foo implements Serializable {
#override
String serialize() {
// TODO: implement serialize
}
#override
void unserialize(String string) {
// TODO: implement unserialize
}
}
You can get an instance like so:
var foo = Serializable.fromSerializedString(Foo, 'someSerializedString');
This might be a bit prettier and natural than the manual method, but keep in mind that it uses reflection with all the problems that can entail.
If you decide to go with a static method and a warning comment instead, it might be helpful to also provide a custom Transformer that scans through all classes implementing Serializable and warn the user or stops the build if any don't have a corresponding static unserialize method or constructor (similar to how Polymer does things). This obviously wouldn't provide the instant feedback the an editor could with instance methods, but would be more visible than a simple comment in the docs.
I think this example is a more Dart-like way to implement the encoding and decoding. In practice I don't think "enforcing" the decode signature will actually help catch bugs, or improve code quality. If you need to make the decoder types pluggable then you can make the decoders map configurable.
const Map<String,Function> _decoders = const {
'foo': Foo.decode,
'bar': Bar.decode
};
Object decode(String s) {
var obj = JSON.decode(s);
var decoder = _decoders[obj['type']];
return decoder(s);
}
abstract class Encodable {
abstract String encode();
}
class Foo implements Encodable {
encode() { .. }
static Foo decode(String s) { .. }
}
class Bar implements Encodable {
encode() { .. }
static Foo decode(String s) { .. }
}
main() {
var foo = decode('{"type": "foo", "i": 42}');
var bar = decode('{"type": "bar", "k": 43}');
}
A possible pattern I've come up with is to create a Factory class that utilize instance methods in a slightly less awkward way. Something like follows:
typedef Constructable ConstructorFunction();
abstract class Constructable {
ConstructorFunction constructor;
}
abstract class Serializable {
String serialize();
Serializable unserialize(String serializedString);
}
abstract class SerializableModel implements Serializable, Constructable {
}
abstract class ModelFactory extends Model {
factory ModelFactory(ConstructorFunction constructor) {
return constructor();
}
factory ModelFactory.fromSerializedString(ConstructorFunction constructor, String serializedString) {
Serializable object = constructor();
return object.unserialize(serializedString);
}
}
and finally a concrete implementation:
class Foo extends SerializableModel {
//required by Constructable interface
ConstructorFunction constructor = () => new Foo();
//required by Serializable interface
String serialize() => "I'm a serialized string!";
Foo unserialize(String serializedString) {
Foo foo = new Foo();
//do unserialization work here to populate foo
return foo;
};
}
and now Foo (or anything that extends SerializableModel can be constructed with
Foo foo = new ModelFactory.fromSerializedString(Foo.constructor, serializedString);
The result of all this is that it enforces that every concrete class has a method which can create a new instance of itself from a serialized string, and there is also a common interface which allows that method to be called from a static context. It's still creating an extra object whose whole purpose is to switch from static to instance context, and then is thrown away, and there is a lot of other overhead as well, but at least all that ugliness is hidden from the user. Still, I'm not yet convinced that this is at all the best way to achieve this.
I suggest you define the unserialize function as named constructor like so:
abstract class Serializable<T> {
String serialize();
Serializable.unserialize(String serializedString);
}
This eliminates the need of static methods.
A possible implementation could look like this:
import 'dart:convert';
class JsonMap implements Serializable<JsonMap> {
Map map = {};
JsonMap() {
}
String serialize() {
return JSON.encode(map);
}
JsonMap.unserialize(String serializedString) {
this.map = JSON.decode(serializedString);
}
}
You can (de)serialize like so:
JsonMap m = new JsonMap();
m.map = { 'test': 1 };
print(m.serialize());
JsonMap n = new JsonMap.unserialize('{"hello": 1}');
print(n.map);
While testing this, I noticed that Dart will not throw any errors at you if you dont actually implement the methods that your class promises to implement with implements. This might just be a hicc-up with my local Dart, though.

Guice - How to use binding annotations to build a list of objects

I have created Guice binding annotations that allow me to bind two different instances of a class depending on the annotation e.g.:
bind(Animal.class).withAnnotation(Cat.class).toInstance(new Animal("Meow"));
bind(Animal.class).withAnnotation(Dog.class).toInstance(new Animal("Woof"));
I was hoping to be able to create a provider method that provides a List that is a dependency for one of my classes, but can't figure out how to use the annotations for this:
#Provider
List<Animal> provideAnimalList() {
List<Animal> animals = new ArrayList<Animal>();
animals.add(#Cat Animal.class); // No, but this is what I want
animals.add(#Dog Animal.class); // No, but this is what I want
return animals;
}
So I was assuming that I would just be able to use the annotations in the argument to add() method of the List... but no.
How should I be approaching this? It seems to me it would be simpler simply to new the two instances of the Animal class and maybe this is not how the binding annotations were meant to be used.
I'd appreciate comments on the best use of the binding annotations in this scenario.
Thanks
If it is really what you want, here a working solution :
public class AnimalModule extends AbstractModule {
#Override
protected void configure() {
bind(Animal.class).annotatedWith(Cat.class).toInstance(new Animal("Meow"));
bind(Animal.class).annotatedWith(Dog.class).toInstance(new Animal("Woof"));
}
#Provides
List<Animal> provideAnimalList(#Cat Animal cat, #Dog Animal dog) {
List<Animal> animals = new ArrayList<Animal>();
animals.add(cat);
animals.add(dog);
return animals;
}
public static void main(String[] args) {
List<Animal> animals = Guice.createInjector(new AnimalModule()).getInstance(Key.get(new TypeLiteral<List<Animal>>() {
}));
for (Animal animal : animals) {
System.out.println(animal);
}
}
}
Annotations :
#Retention(value = RetentionPolicy.RUNTIME)
#BindingAnnotation
public #interface Cat {
}
Output :
Animal{sound='Meow'}
Animal{sound='Woof'}
However :
Don't create specific annotations, seems unnecessary in that case. Use #Named instead,
You may consider Multibindings to solve that problem.

Resources