Reflectable: myAnnotation.annotatedClasses different result CmdApp<>Client - dart

Say I have the following Annotation and 2 classes:
class AppModel extends Reflectable {
final String name;
const AppModel([this.name])
: super(newInstanceCapability, metadataCapability);
}
const appModel = const AppModel();
#appModel
class ImGonnaBePickedUp {
}
#AppModel(' :( ')
class AndImNotPickedUpOnServer_IDoOnWebClient {
}
main() {
appModel.annotatedClasses // that's what I mean by "Picked Up".
}
On CmdApp side (Server): only AndImNotPickedUpOnServer_IDoOnWebClient is given in appModel.annotatedClasses.
On the web side, both classes are given.
Long story short, how do I retrieve classes annotated with direct const constructor calls like in the example above #AppModel(' :( ') (for both CmdApp and Web)?

since version 0.5.4 reflectable classes doesn't support constructors with arguments
This appears in reflectable documentation:
Footnotes: 1. Currently, the only setup which is supported is when the metadata object is an instance of a direct subclass of the class [Reflectable], say MyReflectable, and that subclass defines a const constructor taking zero arguments. This ensures that every subclass of Reflectable used as metadata is a singleton class, which means that the behavior of the instance can be expressed by generating code in the class. Generalizations of this setup may be supported in the future if compelling use cases come up.
one possible solution could be to use a second annotation to handle the name, for example:
import 'package:reflectable/reflectable.dart';
import 'package:drails_commons/drails_commons.dart';
class AppModel extends Reflectable {
const AppModel()
: super(newInstanceCapability, metadataCapability);
}
const appModel = const AppModel();
class TableName {
final String name;
const TableName(this.name);
}
#appModel
class ImGonnaBePickedUp {
}
#appModel
#TableName(' :( ')
class AndImNotPickedUpOnServer_WorksOnWebClient {
}
main() {
print(appModel.annotatedClasses); // that's what I mean by "Picked Up".
print(new GetValueOfAnnotation<TableName>()
.fromDeclaration(appModel.reflectType(AndImNotPickedUpOnServer_WorksOnWebClient)).name);
}
Note: I'm also using drails_common package

Related

Dart cannot override function in generic class with subclass of generic

I am writing an app which deals with both cryptos and stocks. Because they share many common characteristics such as symbol, price, name etc, I created a base class 'instrument' then subclasses for stock and crypto. I have a generic 'manager' class for both, as loading, saving etc are again very similar. However, there are some functions, such as fetching a current price, that need to be implemented differently, so I have extended my generic manager class and I am trying to override the relevant function, i.e. fetchCurrentPrice() in the example below. Dart complains that
'CryptoManager.fetchCurrentPrice' ('Future Function(Crypto)') isn't a valid override of 'Manager.fetchCurrentPrice' ('Future Function(Instrument)').
I don't understand this, as I have defined as type in the manager, and Crypto extends Instrument, so I am fulfilling this criterion. Any idea where I am going wrong?
abstract class Instrument {
String name = 'Instrument';
double currentPrice = 0.0;
Instrument(this.name);
}
class Crypto extends Instrument {
Crypto(super.name);
String contractAddress = '0xBCCFF3FF6...';
}
abstract class Manager<T extends Instrument> {
List<T> instruments = [];
Future<double> fetchCurrentPrice(T instrument) async {
print('Fetching price for generic instrument');
return 12.80;
}
}
class CryptoManager extends Manager {
// this is causing the issue
#override
Future<double> fetchCurrentPrice(Crypto instrument) async {
print('Fetching price for crypto');
return 12.80;
}
}
void main(List<String> args) {
CryptoManager cryptoManager = CryptoManager();
var btcCrypto = Crypto('BTC');
cryptoManager.fetchCurrentPrice(btcCrypto);
}
Your class CryptoManager needs to extend Manager<Crypto>, not just "some Manager, kinda".
class CryptoManager extends Manager<Crypto>

Dart abstract optional parameters

How can I abstract that a methods has optional parameters?
abstract class CopyWith<T>{
T copyWith({}); // Error : Expected an identifier.
}
If I add an identifier like {test} it works and subclasses can have additional arguments
What I want to achieve?
I have a complex state manager, I make some abstraction , the following code is a minimal code, show my problem
import 'dart:collection';
abstract class CopyWith<T> {
T copyWith(OPTIONAL_NAMED_ARGUMENTS);
}
abstract class Manager<K, V extends CopyWith> {
final _map = HashMap<K, V>();
add(K key,V value){
_map[key] = value;
}
void copyWith(K key,OPTIONAL_NAMED_ARGUMENTS) {
assert(key != null);
if (_map.containsKey(key)) {
_map[key].copyWith(OPTIONAL_NAMED_ARGUMENTS);
}
}
}
class User implements CopyWith {
final int id;
final String name;
User({this.id, this.name});
User copyWith({int id, String name}) {
return User(
id: id ?? this.id,
name: name ?? this.name,
);
}
}
class UserManager extends Manager<int, User> {}
void main() {
final userManager = UserManager();
userManager.add(1,User(1,'test'));
userManager.copyWith(1,{test:'test2'})
}
As some one who has faced this issue in my library, I would say the only way is to not put a copyWith in your base class.
Why? Because you should only make a function polymorphic when there IS actually a shared calling convention and behavior. In your example, The way that these two classes perform copyWith is just different. It is, and should be, an error to send a name to Manager.copyWith, because Manager does not have a name to begin with. If you encounter a name inside a Manager.copyWith, that means there is some serious error in your code.
Also, if you actually try to invoke copyWith, as a responsible programmer, you will probably check if you are allowed to pass a name, which is,
if (someObj is User) {
someObj.copyWith(key, name: name);
} else if (someObj is Manager) {
throw IllegalStateError('You should not pass a name to a Manager! What am I supposed to do with the name now?');
}
There, you have already done type checking, so no need to make copyWith polymorphic.
However, some common behaviors can be made polymorphic, like updateKey. You can make Keyable as an interface, and Keyable updateKey(Key key) as an abstract method, and delegate to a non-polymorphic copyWith inside each subclasses.

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

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.

Accessing static variable through subclass method

I'm get null returned when attempting to access a subclass static variable through a overridden subclass accessor:
library resource;
abstract class Resource
{
String name;
String description;
Resource(this.name, this.description);
Resource.map(Map data)
{
...
_getDb()[this] = data;
}
abstract Map _getDb();
}
class Skill extends Resource
{
static Map _skills = {}
Skill.map(Map data) : super.map(data);
Map_getDb()
{
return _skills;
}
}
import 'resource.dart'
void main() {
useVMConfiguration();
test('constructor', () {
Skill skill = new Skill.map({
'name': 'foo'
});
}
}
Here I'm trying to call _getDb() on the (hopefully) now constructed subclass in the super constructor. Despite _skills being instantiated, _getDb() returns null.
Is this possible?
EDIT:
_skills is not present when inspecting this at _getDb():
this Skill [id=0]
description "bar" [id=19]
name "foo" [id=18]
Your example has several flaws as DartEditor shows.
Map_getDb() is missing a space between Map and _getDb().
Is this only in your question or in the code you run too?
abstract Map _getDb(); is also a syntax error.
In Dart a method is made abstract when you don't provide an implementation (; instead of {})
After this fixes the code works fine.

Resources