Dart: how to override a generic method? - dart

Consider my following base class:
abstract class IChat<Message extends IMessage> {
String get getId;
List<T> getUsers<T extends IUser>();
}
Now my extended Model looks like this:
class Chat extends IChat<ChatMessage> {
String id;
List<ChatUser> members;
Chat({this.chat, this.members});
#override
String get getId => id;
#override
List<T> getUsers<T extends IUser>() => members;
}
List<T> getUsers<T extends IUser>() => members; throws an error because I return List<ChatUser> instead of List<T>. How do I override the method to make this work? My ChatUser class obviously also extends IUser.
Edit
#jamesdlin gave one solution: #override List<T> getUsers<T extends IUser>() => members.cast<T>(). It is possible without type casting?

First consider what you actually want your classes to do.
It seems like the subclass has a specific type of IUser that it always wants to return, but a generic function takes its type argument per invocation. So, the type should probably be a property of the class, not of the invocation.
Consider:
abstract class IChat<Message extends IMessage> {
String get getId;
List<IUser> getUsers();
}
class Chat extends IChat<ChatMessage> {
String id;
List<ChatUser> members;
Chat({this.chat, this.members});
#override
String get getId => id;
#override
List<ChatUser> getUsers() => members;
}
Would that satisfy your needs?
As stylistic comments, your code is very C#-like, and doesn't look like Dart. I'd probably declare the classes as:
abstract class Chat<M extends Message> {
String get id;
List<User> get users;
}
class SomeChat extends Chat<ChatMessage> {
#override
final String id;
#override
List<ChatUser> users;
// ...
SomeChat({this.id, List<CharUser> members, ...}) : users = members;
// ...
}

Related

How to <T extend BaseClass> where BaseClass has a factory function?

Following is a simple class that provides a few helper functions for reading and writing data.
class BaseDAO<T> {
final String _modelName;
static late final StoreRef<int, Map<String, Object?>> _store;
BaseDAO(this._modelName) {
_store = intMapStoreFactory.store(_modelName);
}
Future<Database> get _db async => await AppDatabase().database;
Future<void> create(T object) async {
await _store.add(await _db, object.toJSON()); //The method 'toJSON' can't be unconditionally invoked because the receiver can be 'null'.
}
}
Now the issue with this is that the generic type T doesn't have toJSON function. I tried fixing this by writing an abstract class.
abstract class BaseModel {
Map<String, dynamic> toJSON();
factory BaseModel.fromJson(Map<String, dynamic> json);
}
and extending T with BaseModel. This presents all kinds of issues one of them being that I am unable to write an abstract class.
Any solution will be greatly appreciated.
In your case T object is empty. You need to extend it to some object which provides a method toMap().
Example:
class BaseDAO<T extends BaseModel> {
final String _modelName;
static late final StoreRef<int, Map<String, Object?>> _store;
BaseDAO(this._modelName) {
_store = intMapStoreFactory.store(_modelName);
}
Future<Database> get _db async => await AppDatabase().database;
Future<void> create(T object) async {
await _store.add(await _db, object.toMap()); // <- Dart see that this object extends to BaseModel and has a method `toMap()`,
}
}
abstract class BaseModel {
Map<String, dynamic> toMap();
}
class User extends BaseModel {
User({this.name});
final String? name;
#override
Map<String, dynamic> toMap() => {'name': name};
}
Future<void> create() async {
final user = User(name: 'Superman');
final base = BaseDAO('ModelName');
await base.create(user); // <- The user object will be added as `Map`.
}

Getting TypeLiterals via method to reduce verbosity

I want to reduce the verbosity of binding a generic interface to several implementations based on TypeLiterals...
I have an interface FieldComputer<T extends ComputeField> where ComputeField is my model interface.
Tried extending a ShortLiteral class (see example below) to reduce the verbosity but it doesn't seem to work. would like to understand why?
// A typical Guice Module
public class ConflationModule implements Module {
// typical overridden configure method
public void configure(Binder binder) {
// Works but is verbose....
bindField_1(binder,
new TypeLiteral<FieldComputer<ComputeFieldImpl>>(){},
FieldComputerImpl.class);
// Doesn't Work
bindField_1(binder,
new ShortLiteral<ComputeFieldImpl>(){},
FieldComputerImpl.class);
// Doesn't Work
bindField_2(binder,
new ShortLiteral<ComputeFieldImpl>(){},
FieldComputerImpl.class);
}
private static class ShortLiteral<CF extends ComputeField> extends TypeLiteral<FieldComputer<CF>>{}
private <CF extends ComputeField> void bindField_1(Binder binder,
TypeLiteral<FieldComputer<CF>> typeLiteral,
Class<? extends FieldComputer<CF>> clazz
) {
binder.bind(typeLiteral).to(clazz);
}
private <CF extends ComputeField> void bindField_2(Binder binder,
ShortLiteral<CF> typeLiteral,
Class<? extends FieldComputer<CF>> clazz
) {
binder.bind(typeLiteral).to(clazz);
}
}
I would suggest you just create TypeLiteral programmatically, here is an example how to do it with different implementations of one interface:
class TypeLiteralModule extends AbstractModule {
#Override
protected void configure() {
customBind(String.class, StringConsumer.class);
customBind(Integer.class, IntegerConsumer.class);
}
private <T> void customBind(Class<T> clazz, Class<? extends Consumer<T>> impl) {
var typeLiteral = (TypeLiteral<Consumer<T>>) TypeLiteral.get(Types.newParameterizedType(Consumer.class, clazz));
bind(impl).in(Singleton.class);
bind(typeLiteral).to(impl);
}
}
class StringConsumer implements Consumer<String> {
#Override
public void accept(String s) {
}
}
class IntegerConsumer implements Consumer<Integer> {
#Override
public void accept(Integer s) {
}
}

How to create a base factory and override it on child class in Flutter

So I have a class like Question like bellow:
#JsonSerializable()
class Question {
String id;
String content;
Question({this.id, this.content});
factory Question.fromJson(Map<String, dynamic> json) =>
_$QuestionFromJson(json);
Map<String, dynamic> toJson() => _$QuestionToJson(this);
}
Please keep in mind that those _$QuestionFromJson and _$QuestionToJson comes from this library https://pub.dev/packages/json_serializable
Say I have many class like that which have a fromJson factory and a toJson method. I want to create a base class that contains those 2 method. A base model is easy for toJson as bellow:
abstract class BaseModel {
Map<String, dynamic> toJson();
}
But what about the factory method, I have no idea how to declare them then override it simply like:
#override
factory Question.fromJson(Map<String, dynamic> json) =>
_$QuestionFromJson(json);
EDIT:
My idea of using this is because I want to create a converter utility that I only need to pass in the class of the result like Converter.listFromJson<MyClass>(jsonString). For now, the helper is:
static List<T> listFromJson<T>(jsonString, Function mappingFunction) {
return myJsonMap.map(mappingFunction).cast<T>().toList();
}
so I have to map each item by passing the map function every time I use this helper method:
Converter.listFromJson<Question>(
jsonMap, (item) => Question.fromJson(item));
There'are a few more class that needs to be convert to the list like this. I want to reuse the method without the (item) => Question.fromJson(item) method part. That's why I want to create a base class that have the factory fromJson method so that I can use it in the converter
return myJsonMap.map((item) => BaseModel.fromJson(item)).cast<T>().toList();
then I just simply call
Converter.listFromJson<Question>(jsonMap);
Thank you for your time.
i don't know if i got you correctly, that's what i understood from your question
abstract class BaseModel{
BaseModel();
BaseModel.fromJson(Map<String,dynamic> json);
}
class Question extends BaseModel{
final String id;
final String name;
Question({this.id,this.name}): super();
#override
factory Question.fromJson(Map<String, dynamic> json) {
return Question(
id: json['id'],
name: json['name']
);
}
}
void main(){
Map<String,dynamic> json = {'id': "dsajdas",'name': 'test'};
Question question = Question.fromJson(json);
print('question: ${question.id}');
}
That was my approach but you can't do such a thing. There is a workaround by declaring .fromJson(json) in a variable. Look at my sample codes, hope you can get an idea.
class Categories {
final String id;
String name;
String image;
Categories({this.id, this.name, this.image});
Categories.fromJson(dynamic json)
: id = json['id'],
name = json['name'],
image = json['image'];
}
class CategoriesModel extends AppModel<Categories> {
List<Categories> list = [];
Function fromJson = (dynamic json) => Categories.fromJson(json);
}
class AppModel<T> {
List<T> list = [];
Function fromJson;
List<T> getList() {
if (this.list.isNotEmpty) return this.list;
List<dynamic> list = GetStorage().read('tableName');
list.forEach((data) {
this.list.add(fromJson(data));
});
return this.list;
}
}

List property inheritance

The parser is complaining that the property inheritor .list is not subtype of ModelList.list, but LeadsGroup does inherit from Model.
Is this wrong? What is the correct way to do this?
My base class:
abstract class ModelList {
List<Model> get list;
set list(List<Model> n);
}
The inheritor:
class ListLeadsGroup extends ModelList {
List<LeadsGroup> list;
}
class LeadsGroup extends Model {
}
If you have code like
class Foo extends ModelList {}
ModelList ml = new ListLeadsGroup();
ml.list.add(new Foo());
ml.list is of type Model, therefore adding Foo should be legit.
But this very likely is not what you want.
This is why List<ListLeadsGroup> can't override List<Model>.
This should do what you want:
abstract class ModelList<T extends Model> {
List<T> get list;
set list(List<T> n);
}
class ListLeadsGroup extends ModelList<LeadsGroup> {
List<LeadsGroup> list;
}
class LeadsGroup extends Model {
}
just copied from Matan Lurey's comment on Gitter
import 'package:func/func.dart';
class ModelRegistry {
final _factories = <Type, Func0<Model>>{};
Model create(Type type) => _factories[type]();
void register(Type type, Model factory()) {
_factories[type] = factory;
}
}
main() {
var registry = new ModelRegistry();
registry.register(FooModel, () => new FooModel());
var foo = registry.create(FooModel);
}
found a solution using the new keyword covariant. Now the classes that extends ModelList can override the List<Model> list without warnings.
#serializable
abstract class ModelList extends ModifiedModel
implements Model {
Type get listType {
throw new UnimplementedError();
}
List<Model> get list;
set list(covariant List n);
}

Sesame alibaba mapping subclasses

I'm programming an application Web (Semantic Web) and for storing the triples, using sesame, and for mapping of data alibaba. My question is, that way I have to implement the classes,to that at the base of triplets is store an object as a subclass of another , try interfaces but I got no results , below I present the "entities":
the parent class:
import java.math.BigInteger;
import org.openrdf.annotations.Iri;
#Iri(Parent.NS + "Parent")
public interface Parent {
public static final String NS = "http://www.spelta.ec/ontology/example#";
#Iri(Parent.NS +"code")
BigInteger getCode();
#Iri(Parent.NS +"code")
void setCode(BigInteger code);
#Iri(Parent.NS+"description")
String getDescription();
#Iri(Parent.NS+"description")
void setDescription(String description);
}
The child class:
import java.math.BigInteger;
public class Child implements Parent {
private BigInteger code;
private String description;
#Override
public BigInteger getCode() {
return code;
}
#Override
public void setCode(BigInteger code) {
this.code = code;
}
#Override
public String getDescription() {
return description;
}
#Override
public void setDescription(String description) {
this.description = description;
}
}
to consult the store of triples, should define an instance of the Children class is a subclass of Parent
many thanks

Resources