Dart: How to add elements to a Map inherited from parent class - dart

I have a class with a Map:
class A {
Map<String,String> get data => { "index1": "value1" };
// other methods and props
}
And I need to have a class B that extends it, and adds new elements to the map. For example, I want to have in B instances both index1 and index2 in the map:
class B extends A {
#override
Map<String,String> get data => { ...data, "index2": "value2"}
}
But the spread operator is for lists... also I dont' know if I can access data in the child like this.
Anyone can point me in the right direction?
Many thanks!

Spread operator can be used for maps also.
In order to access member of parent class you should use super:
super.data
Like this:
class B extends A {
#override
Map<String,String> get data => { ... super.data, "index2": "value2"};
}

Related

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.

How to capture the generic type of a generic constraint?

Consider the following generic class:
class Foo<T extends Bar<dynamic>> {}
How can I obtain the generic argument of Bar at compile time?
I would expect the following code to print int, but it prints dynamic:
class Bar<T> {}
class Foo<T extends Bar<dynamic>> {
Foo(this.value) {
_debugBarType(value);
}
final T value;
void _debugBarType<A>(Bar<A> value) {
print(A);
}
}
void main() {
Foo<Bar<int>>(Bar());
}
I know I could do:
class Foo<A, Bar<A>> {}
But I would like to define the Foo class using a single generic parameter instead of two.
This is currently not possible to do on any class.
There's currently a pending feature request on Dart to support such use-case: https://github.com/dart-lang/language/issues/620
It's worth noting that there's a workaround if you can add a method on the class concerned.
For example, say you have a generic class Model<T>:
class Model<T> {
T value;
}
Then you can add a "capture" method as such:
class Model<T> {
T value;
R capture<T>(void cb<P>(P value)) => cb<T>(value);
}
This then allows you to write:
void someFunction<T extends Model<dynamic>>(T model) {
model.capture(<P>(value) {
// `P` will be the captured type instead of `dynamic`
});
}

How do I call a method from an extended class?

i have no experience with extended classes
so don't be shocked... that's what I got:
the 'basic class' I want to extend in my models
to avoid repeat fromJson/toJson every 2 lines
import 'dart:convert';
class BaseModel {
Map<String, dynamic> json2Map(String json) => jsonDecode(json);
String map2Json(Map<String, dynamic> map) => jsonEncode(map);
json2List(String jsonList) {
List<Map<String, dynamic>> _list = [];
jsonDecode(jsonList).forEach((_json) => _list.add(jsonDecode(_json)));
return _list;
}
mapList2Json(List<Map<String,dynamic>> list) {
List<String> jsonList= [];
list.forEach((_map) => jsonList.add(map2Json(_map)));
return jsonEncode(jsonList);
}
}
and here is one of the class that extends this:
import 'package:bloc_hub/models/base_model.dart';
class Info extends BaseModel {
final String name;
final String company;
Info({this.name,this.company});
factory Info.fromMap(Map<String, dynamic> json) => new Info(
name: json['name'],
company: json['company'],
);
Map<String, dynamic> toMap() {
var map = new Map<String, dynamic>();
map['name'] = name;
map['company'] = company;
return map;
}
}
(I'm in a streambuilder and client.info is a json)
then... when I try to call 'json2map'
which is from the extended class...
Info info = Info.fromMap(json2Map(client.info));
i get this:
[dart] The method 'json2Map' isn't defined for the class 'ListPage'. [undefined_method]
what did I get wrong?
if I wasn't clear don't refrain to ask me anything
thank you for your help
[edit: bonus question
how a mixin is different from what I'm doing?]
json2Map is an instance method of BaseModel, so in order to call it you must use an instance of BaseModel or a class that extends it (like Info), like:
var b = new BaseModel();
b.json2Map(something);
The error message says you're calling it from ListPage, so the method is not found.
Alternatively, you could make the methods static and call it like BaseModel.json2Map(...) (without an instance).
There are some good explanations about mixins here (with Python examples, but the concepts are the same for Dart). I guess in your example it would make more sense to have a mixin with JSON related functions, since you could use them in other kind of objects.

how can i initialize super class variables in dart language?

Simply i have to classes child and parent class i am new in dart language all i need to assign super class properties from child class
this is super class structure
class Trip{
final int id;
final String title;
final double price;
Trip({this.id,this.title,this.price});
}
and this is child class
class FullTrip extends Trip{
final String data;
FullTrip({this.data}) : super(id:id,title:title,price:price);
}
sure this not working at all
the question is : how can i initialize instance from FullTrip and pass variable for FullTrip and Trip(super class)
thanks in advance
You need to repeat the parameters in the subclass.
class FullTrip extends Trip{
final String data;
FullTrip({this.data, int id, String title, double price}) : super(id:id,title:title,price:price);
}
There are discussions about reducing such boilerplate for constructors, but nothing is decided yet as far as I know.
User super-parameters, which were added in Dart 2.17. For example, say this is your class:
class Parent {
Parent({
int? i,
bool b = false,
required String s,
});
}
Old way (boilerplate code)
Earlier you had to do something like this:
class Child extends Parent {
Child({
int? i,
bool b = false,
required String s,
}) : super(
i: i,
b: b,
s: s,
);
}
New way (neat and clean)
But now you can get rid of those boilerplate code.
class Child extends Parent {
Child({
super.i,
super.b = false,
required super.s,
});
}
If you want to re-initialize in a subclass the not private variables of an extended or implemented upper class before compiling, simply use #override. Look at this example
(if you want to try the code, have in mind it supports null safety. If your test doesn't, simply delete the ? signs.)
class Go {
String? name = "No name";
}
class Foo implements Go { //use either implements or extends
#override
String? name = "Foo";
}
class Doo extends Go { //use either implements or extends
#override
String? name = "Doo";
}
Use case example: In the code above, you can see that in our upper class we have this String name variable. Then in the subclasses we can simply override that variable. After that, in main we can now for example do something like iterating through a List<Go>, access what we wanted to and then trigger something, like printing the name:
void main() {
List<Go> foos = [
Go(),
Foo(),
Doo(),
];
for(Go x in foos){
print(x.name);
}
}
Output:
No name
Foo
Doo
This works if you use either the extends or implements keywords.

How are arguments passed into the parameter list of ClassMirror.newInstance(...)? [duplicate]

I'm perfectly willing to play with this until I get it right, but was hoping someone might give me a hint. The parameter is declared in the docs (gen-dartdocs/dart-mirrors/ClassMirror/newInstance.html) as
InstanceMirror newInstance(Symbol constructorName,
List positionalArguments,
[Map<Symbol,dynamic> namedArguments]);
There is a nice writeup on the format of positionalArguments and namedArguments in the docs. However, it is just a little on the abstract side of my current tolerance level.
A decent discussion also exists at
http://japhr.blogspot.com/2014/06/dart-factory-method-pattern.html
But, alas, no examples of actually passing args into the method.
In my case, I would like to simply pass two args, "title" and "description" into an unnamed subclass constructor.
Here's my code so far:
file: item.dart
import 'dart:mirrors';
abstract class Item {
String title;
String description;
factory Item(String type) {
MirrorSystem libs = currentMirrorSystem();
LibraryMirror lib = libs.findLibrary(new Symbol('app.models'));
Map<Symbol, Mirror> classes = lib.declarations;
// To do: handle exception if class not found
ClassMirror cls = classes[new Symbol(type)];
// TODO:
// verify each subclass has no-arg ctor
// determ how to pass args to ctor.
InstanceMirror inst = cls.newInstance(new Symbol(''), []);
return inst.reflectee;
}
// conflicts w/ Item factory
// Item(this.title, this.description);
}
And here's the class that gets instantiated:
file: model.dart
library app.models;
import 'item.dart' show Item;
/// The barebones model for a codelab. Defines constants used for validation.
class Codelab implements Item {
// ...
}
Finally, here is how the Item factory is called. ItemElement is the superclass of its own hierarchy, subclassed by CodelabElement:
file: item_element.dart:
import 'item.dart' show Item;
class ItemElement {
Item item;
final String itemType;
ItemElement() {
item = new Item(itemType);
}
// ...
}
And CodelabElement:
file: codelab_element.dart
import 'model.dart' show Codelab;
import 'item_element.dart' show ItemElement;
class CodelabElement extends ItemElement {
final itemType = "Codelab";
CodelabElement() : super() {}
//...
}
And then:
file: main.dart
void main() {
var element = new CodelabElement();
}
Currently, the new Codelab instance is returned from newInstance() (very cool), but it doesn't contain the inherited 'title' and 'description' attrs.
Maybe it has something to do with my being unclear on the usage of "extends" and "implements".
This should work
cls.newInstance(new Symbol(''), ['a', 1] /*,
{#arg1Name: 'arg1Value', #arg2Name: 'arg2Value'}*/ );
and is like
new MyClass('a', 1, arg1Name: 'arg1Value' /*, arg2Name: 'arg2Value'*/);
Just saw, Named arguments are not implemented.
You can try it in DartPad

Resources