Create class instance from string in dartlang - dart

I have created this class
class Opacity {
String a,b,c;
Opacity({this.a, this.b,this.c});
}
And I'm trying to dynamically create an instance of this class only using strings and an hashmap for arguments.
String type = "Opacity";
List<String> args = {'a': 'a', 'b': 'b','c': 'c'}
And I have one constraint, I can't modify the Opacity class.
For creating the instance I thought about using reflection to dynamically create the class from string but I can't figure out how to pass the arguments dynamically.

For passing arguments dynamically to the constructor you can use newInstance method of ClassMirror.
For example
MirrorSystem mirrors = currentMirrorSystem();
ClassMirror classMirror = mirrors.findLibrary(Symbol.empty).declarations[new Symbol('Opacity')];
print(classMirror);
var arguments = {'a': 'a', 'b': 'b', 'c': 'c'}.map((key, value) {
return MapEntry(Symbol(key), value);
});
var op = classMirror.newInstance(Symbol.empty, [], arguments);
Opacity opacity = op.reflectee;
print("opacity.a: ${opacity.a}");
print("opacity.b: ${opacity.b}");
print("opacity.c: ${opacity.c}");

Going from a string to a source name, and further to the thing denoted by that source name, is reflection. It's only available through the dart:mirrors library, or if you generate code ahead-of-time, perhaps using package:reflectable.
This is a point where Dart differs from a language like JavaScript, where you can inspect all values at run-time.
Without reflection, the only way you can call a constructor is if you have actual code performing that call in your code. That would mean that you have to have code like Opacity(a: ..., b: ..., c: ...) at least in one place in your code.
You could define a function like:
Opacity createOpacity(Map<String, String> args) =>
Opacity(a: args["a"], b: args["b"], c: args["c"]);
Then you could perhaps register it by name as:
Map<String, Function> factories = {"Opacity": createOpacity};
and finally use it as:
var type = "Opacity";
var args = {'a': 'a', 'b': 'b', 'c': 'c'};
Opacity myOpacity = factories[type](args);

Related

Generic method that returns List<T> instead returns List<dynamic>

I tried writing a simple generic method that would iteratively copy a nested List, for example a List<List<int>>. But unfortunately, the recursive call seems to always return List<dynamic>, so I get the following error
The argument type List<dynamic> can't be assigned to the parameter type T
List<T> listDeepCopy<T>(List<T> list){
List<T> newList = List<T>();
list.forEach((value) {
if( value is List ){
newList.add(listDeepCopy(value)); // <-- listDeepCopy() always returns List<dynamic>
}
else{
newList.add(value);
}
});
return newList;
}
So if I call
List<List<int>> list = [[1,2],[3,4]];
List<List<int>> copy = listDeepCopy(list);
T is List<int>
value is T - i.e. List<int>
listDeepCopy(value) should equal listDeepCopy<List<int>>, which would return a List<int>, which should be possible to add to newList, which is a List<List<int>>
Where am I going wrong here, and how can I make something like this work?
I probably would implement it as:
List<T> listDeepCopy<T>(List<T> list) {
var copy = list.toList();
for (var i = 0; i < copy.length; i += 1) {
var element = copy[i];
if (element is List) {
copy[i] = listDeepCopy(element) as T;
}
}
return copy;
}
void main() {
List<List<int>> list = [
[1, 2],
[3, 4]
];
List<List<int>> copy = listDeepCopy(list);
list[0][0] = 99;
print(copy); // Prints: [[1, 2], [3, 4]]
}
A problem with your approach is that Dart cannot properly infer the generic type parameter for that recursive listDeepCopy(value) call. value is of type T that is known to be a List (which is shorthand for List<dynamic>), and I am not aware of a way to extract the static element type. (Maybe #lrn will see this and provide a better, more complete explanation.)
In such a case, it's better to rely on polymorphism by calling a method on the List that returns a copy of itself: .toList().
(As an example where this matters, consider a shallow copy scenario:
List<T> shallowCopy1<T>(List<T> list) => <T>[...list];
List<T> shallowCopy2<T>(List<T> list) => list.toList();
extension StaticType<T> on T {
Type get staticType => T;
}
void main() {
List<num> list = <int>[1, 2, 3];
var copy1 = shallowCopy1(list);
var copy2 = shallowCopy2(list);
print('original: staticType: ${list.staticType}, runtimeType: ${list.runtimeType}');
print('copy1: staticType: ${copy1.staticType}, runtimeType: ${copy1.runtimeType}');
print('copy2: staticType: ${copy2.staticType}, runtimeType: ${copy2.runtimeType}');
}
Although both copies preserve the static type of the original List, only copy2 preserves the object's actual (runtime) type. A proper copy depends on the runtime type of the object being copied, and the only robust way to do that is for the object to create a copy of itself.)
You can't do it the way you are trying to do it.
The problem is that deepClone<T> converts a List<dynamic> to a List<T> (which is fine) and then tries to convert elements that are themselves lists into typed list ... but you don't know the type.
In effect, when you check that value is List, you don't know what kind of list to convert it to.
There are two cases:
Either T is List<X> or Iterable<X> for some type X, but you have no way to get your hands on that X. Dart doesn't allow you to destructure types at runtime.
Or T is Object or another general supertype with no "list element" type inside it, and then you simply do not have any information about what List type to convert the nested list to. (That's actually the simplest case, because then you should simply not deepClone the list at all).
There is a way to figure out which case you are in (<T>[] is List<Iterable<Object?>>), but it won't help you in the former case, unless you want to do an exhaustive search of all the possible types that X might be.
What I'd do instead is to build a converter, instead of using a single function.
abstract class Cloner<T> {
const factory Cloner() = _ValueCloner<T>;
T clone(dynamic source);
Cloner<List<T>> get list => _ListCloner(this);
}
abstract class _BaseCloner<T> implements Cloner<T> {
const _BaseCloner();
Cloner<List<T>> get list => _ListCloner<T>(this);
}
class _ValueCloner<T> extends _BaseCloner<T> {
const _ValueCloner();
T clone(dynamic source) => source as T;
}
class _ListCloner<T> extends _BaseCloner<List<T>> {
final Cloner<T> _base;
_ListCloner(this._base);
List<T> clone(dynamic source) =>
<T>[for (var o in source as List<dynamic>) _base.clone(o)];
}
Then, if you actually know the type of the data, you can build your cloner as:
var typedList =
Cloner<int>().list.list.clone(
<dynamic>[<dynamic>[1, 2], <dynamic>[3, 4]]);
which yields a List<List<int>> with the value <List<int>>[<int>[1, 2], <int>[3, 4]].

How do I get a nested element in a List or a Map with a provided List in Dart?

Supposing that I have a List and a Map:
Map<String, dynamic> rootMap = {
'a': 'b',
'c': ['d', ['e', 'f']],
'g': {'h': 'i', 'j': {'k': 'l'}}
};
List<dynamic> rootList = [
11, 22, [33, 44, [55, 66]]
];
...which means I can access the value 'l' in rootMap as such:
var valueL = rootMap['g']['j']['k'];
...which also means I can access the value 66 in rootList as such:
var value66 = rootList[2][2][2]
However, assuming the user will provide something like a path to data, let's say, in a List form as such:
List<dynamic> dataPathForRootMap = ['g', 'j', 'k'];
List<dynamic> dataPathForRootList = [2, 2, 2];
I would like to use these lists (paths for data) in order to access the data in rootMap and rootList.
Note that both are List<dynamic> because the data might be complicated, meaning that there might be Lists under Map or Maps under Lists.
I came up with a solution as such:
var resolvedRootMapData = rootMap;
for (var path in dataPathForRootMap) {
resolvedRootMapData = resolvedRootMapData[path]
}
// at the end, the value of `resolvedRootMapData` will be `l`
You can apply the same logic to rootList as well. I want to focus on rootMap.
I do not like this approach for a couple of reasons:
This is not null safe. The user might provide a false path data and it would fail. Of course, this can be avoidable but still...
This does not look quite idiomatic.
The type of resolvedRootMapData is inconsistent on each for-iteration.
So, the question is:How do I get a nested element in a List or a Map with a provided List in Dart? Is there a solution to this that I am not aware of maybe?
Thanks in advance.
Environment
The output of flutter --version:
Flutter 2.8.1 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 77d935af4d (3 weeks ago) • 2021-12-16 08:37:33 -0800
Engine • revision 890a5fca2e
Tools • Dart 2.15.1
The code that you don't like is probably the best you can do with the data you have.
As you point out, the types of the individual lists or maps that you traverse are not the same, but the input array of indices is absent of any type information, so you will need to do dynamic lookups. There is no way to make this well-typed (enough to compile) without dynamic lookups or casts.
If the data are heterogenous in themselves, it's probably impossible to do anything.
If the data are at least typeable without using dynamic or Object, then it's technically possible to define a typed path that preserves type safety. (Not null safety, you're never safe when lookup up in a map.)
If you really want to do type safe lookups, the following is an example of such an approach. It uses reverse ordering of lookups, because it's much much easier that way (because it's effectively building as stack).
abstract class Lookup<T, V> {
Lookup<List<T>, V> operator [](int index) =>
ListLookup<T, V>(this, index);
Lookup<Map<K, T>, V> get<K>(K key) =>
MapLookup<K, T, V>(this, key);
V call(T structure);
}
class ValueLookup<T> extends Lookup<T, T> {
T call(T value) => value;
}
class ListLookup<T, V> extends Lookup<List<T>, V> {
final int _index;
final Lookup<T, V> _rest;
ListLookup(this._rest, this._index);
V call(List<T> list) => _rest(list[_index]);
}
class MapLookup<K, T, V> extends Lookup<Map<K, T>, V> {
final K _key;
final Lookup<T, V> _rest;
MapLookup(this._rest, this._key);
V call(Map<K, T> map) => _rest(map[_key] as T);
}
Lookup<V, V> lookup<V>() => ValueLookup<V>();
Then you can write the path [1]["foo"][2] as
void main(){
List<Map<String, List<int>>> structure = [{}, {"foo": [0, 0, 42]}];
var path = lookup<int>()[2].get("foo")[1]; // path [1]["foo"][2]
// Type: Lookup<List<Map<String, List<int>>>>
var result = path(structure); // 42
print(result);
}
Most likely, that's massive overkill for what you need.
Try to figure out what your precise needs are, and whether a more object oriented data structure will better serve you.

Seeking a safe translation of a Python dict as a return type to Dart

Once in a while we all need to quickly return multiple values from a function, and look for a way to create a new type on the fly.
In Python I can return a tuple
def get_trio1():
return (True, 23, "no")
(_, first1, second1) = get_trio1()
print(first1)
print(second1)
ignore one of the values, and retrieve both of the other two on the fly in one assignment.
I can likewise return an array.
def get_trio2():
return [True, 23, "no"]
[_, first2, second2] = get_trio2()
print(first2)
print(second2)
But both of these are brittle. If I edit the code to add a value, particularly if it's within the three already defined, the revised code could fail silently.
Which is why the nicest solution is to create a dict on the fly.
def get_trio3():
return {"b": True, "i": 23, "s": "no"}
r = get_trio3()
print(r["i"])
print(r["s"])
The use of named members means that maintaining the code is considerably safer.
What is the closest I can do to get the same safety in Dart? Is defining a class for the return type necessary?
In case it matters, the context is avoiding List<List<dynamic>> when returning a future.
Future<List<dynamic>> loadAsset() async =>
return await Future.wait([
rootBundle.loadString('assets/file1.txt'),
rootBundle.loadString('assets/file2.txt'),
]);
Update
Using Stephen's answer for a future introduces a problem. Future.wait is hardwired to use an array Iterable.
Future<Map<String, dynamic>> loadAsset() async =>
return await Future.wait({
"first": rootBundle.loadString('assets/file1.txt'),
"second": rootBundle.loadString('assets/file2.txt'),
});
Your loadAsset function returns a Future<List<dynamic>> because that's how you declared it. You could have declared it to return a Future<List<String>> instead.
Future.wait is hardwired to use an array.
Especially since Dart is a statically-typed language, you can't really expect it to take both a List and some Map with your custom semantics. You could write your own version:
Future<Map<String, T>> myFutureWait<T>(Map<String, Future<T>> futuresMap) async {
var keys = futuresMap.keys.toList();
var values = futuresMap.values.toList();
var results = await Future.wait<T>(values);
return Map.fromIterables(keys, results);
}
Use a map.
Map<String, dynamic> foo() => {'A': 'a', 'B': 'b', 'C': false }
var result = foo();
print result['B']; // prints b;

Compile-time foreach outside function body

Is there any way to have a foreach outside a function body for ex. generating code.
My scenario is that I have an associative array at compile-time that I need to use to generate specific fields. Unfortunately I can't really use a foreach outside of a function body to generate the members.
Right now I am using a work-around where I have a few mixins where I give one AA to the first mixin and that mixin converts the AA to an array and passes it to the second mixin, the second mixin is recursive with itself by ng itself until there is no more member, while also calling the first member in the array, which calls a third mixin that I can use to generate code.
It's not as smooth and dynamic as I really would want it to be and I was wondering if anyone has a better solution.
Here is my solution
// First mixin that takes the associative array and a string for the mixin to handle the items
mixin template StaticForEachAA(TKey,TValue, TKey[TValue] enumerator, string itemMixin) {
enum array = arrayAA!(TKey,TValue)(enumerator); // Converts the AA to an array of key-value pair structs
alias ArrayType = KeyValuePair!(TKey,TValue);
mixin StaticForEachArray!(ArrayType, array, itemMixin); // Calls second mixin with the array
}
// The second mixin that "fake loops" the array
mixin template StaticForEachArray(T, T[] array, string itemMixin) {
static if (array.length) {
import std.string : format;
mixin(format("mixin %s!(T, array[0]);", itemMixin)); // Mixins the itemMixin to handle the current item
mixin StaticForEachArray!(T, array[1 .. $], itemMixin); // slices the array to remove the item we just handled
}
}
// The third mixin that can be used to do whatever has to be done with item
mixin template StaticForEachItem(T, T item) {
import std.conv : to;
pragma(msg, to!string(item));
}
And to do the "fake foreach" for an associative
enum AA = [0 : 1, 1 : 2, 2 : 3];
mixin StaticForEachAA!(int, int, AA, "StaticForEachItem");
This will print the key-value pairs from AA at compile-time.
Leveraging the power of compile-time functione excution (CTFE) you could make a helper function that generates code for you using the data from an associative array (AA) you provide.
import std.string : format;
string generateCodeForEachAA(TKey, TValue)(TValue[TKey] data, string foreachBody)
{
string result;
foreach(k, v ; data)
{
result ~= format(foreachBody, k, v);
}
return result;
}
This function turns the given AA data into a string by formatting the given foreachBody with each AA element. The returned string can then be mixin'ed:
enum Data = [ 0 : 1, 1 : 2, 2 : 3 ];
enum Code = generateCodeForEachAA(Data, q{ pragma(msg, "%1$s => %2$s"); });
pragma(msg, "Code: " ~ Code);
mixin(Code);
Output:
Code: pragma(msg, "0 => 1"); pragma(msg, "1 => 2"); pragma(msg, "2 => 3");
0 => 1
1 => 2
2 => 3
Using this to generate members within a struct:
struct Foo
{
enum Members = [ "foo": 123, "bar": 42 ];
mixin(generateCodeForEachAA(Members, q{ typeof(%2$s) %1$s = %2$s; }));
}
void main()
{
import std.stdio : writeln;
Foo f;
writeln("foo: ", f.foo);
writeln("bar: ", f.bar);
}
Output:
foo: 123
bar: 42

Groovy - with closure with multiple references

I'm trying to parse a JSON data and assign it to a POJO in Grails.
I started with
obj.param=jsonRequest.jsonWrap.attrib.something.jsonParam
After some experimenting and refactoring, it looks like this now.
jsonRequest.jsonWrap.attrib.something.with {
obj.param1=jsonParam1
obj.param2=jsonParam2
//...
}
}
Now, can I avoid the repeated use of obj reference?
I'm imagining that your actual starting point is something like the following. On the JSON side:
import groovy.json.JsonSlurper
String jsonText = '''{
"jsonWrap":{
"attrib":{
"something":{
"jsonParam1": "value1",
"jsonParam2": "value2",
"jsonParam3": "value3",
"jsonParam4": "value4",
"jsonParam5": "value5"
}
}
}
}'''
def jsonRequest = new JsonSlurper().parseText(jsonText)
On the Groovy side:
class ObjectType {
def param1, param2, param3, param4, param5
}
def obj = new ObjectType()
Now, if I had any control over how either the JSON side or the Groovy side are defined then I would do my darnedest to ensure that the property names of the JSON "something" object are exactly the same as the property names in the Groovy "ObjectType" class. For example, like this:
class ObjectType {
def jsonParam1, jsonParam2, jsonParam3, jsonParam4, jsonParam5
}
Then, unmarshalling the "something" object into Groovy is as simple as this:
def obj = new ObjectType(jsonRequest.jsonWrap.attrib.something)
Only one reference to the JSON object. Only one reference to the Groovy object. And the former is used to instantiate the latter. And furthermore, notice that there is no need to reference the properties at all. That is, JSON objects from the slurper are instances of Map, so if the property names match up, you can use the default "Map constructor" syntax.
If, however, you do not control property naming in either set of objects, I would still recommend a different Map-based short-cut. First define a constant Map from one set of property names to the other, like so:
def map = [param1:"jsonParam1", param2:"jsonParam2", param3:"jsonParam3",
param4:"jsonParam4", param5:"jsonParam5"]
Then I would use something like this for the object unmarshalling:
def obj = new ObjectType().with { o ->
jsonRequest.jsonWrap.attrib.something.with { j ->
map.each { oParam, jParam -> o[oParam] = j[jParam] }
}
o
}
i don't think there is a trivial way to trick groovy into "use objectA, if getting is needed and objectB for setting". If obj above is a map or you can apply a map to this object, then you could produce a map in your with block and use this. If you have to have nested structures then more work is needed.
def jsonParam = new Expando([ p1: 'p1', p2: 'p2', p3: 'p3', ])
def obj = new Expando(
jsonParam.with{
[
param1: p1,
param3: p3,
] // `with` will return this map
})
assert obj.param1==jsonParam.p1
assert obj.param3==jsonParam.p3
I use expandos for simple code.

Resources