With the dartz Dart lib, how can you construct an IMap from key-value pairs? - dart

I see the factory constructor factory IMap.fromPairs(FoldableOps<dynamic, Tuple2<K, V>> foldableOps, Order<K> kOrder), but how do you use FoldableOps to be able to pass an Iterable<Tuple2<X,Y>> into it?

After consulting the aforementioned art installation (you know, in lieu of official documentation) as well as some sample code in the repo, I believe this is the way to do it:
iList<Tuple<K, T>> tuples = ...;
IMap<K, T> map = IMap.fromPairs(tuples, Order<K>);
Where what you pass for Order<K> depends on the key type in the tuples. If it's a native type like int or String, you can pass IntOrder or StringOrder. Otherwise, you will need to create an Order implementation for that type, e.g.:
class Foo extends Comparable {
...
}
Order<Foo> fooOrder = ComparableOrder<Foo>();
iList<Tuple<Foo, dynamic>> tuples = ...;
iMap<Foo, dynamic> map = iMap.fromPairs(tuples, fooOrder);

Related

Is there a neater way to map member functions in dart?

Dart has a handy map function on iterables, and it accepts a lambda. So I can write something like:
// Stupid example class
class Foo {
int v;
int v2() { return v*v; }
}
List<int> mapFoos(List<Foo> foos) {
return foos.map( (Foo f) => f.v2() );
}
But this feels a little clunky to me. I'm used to being able to tell map to use the member function directly, something that would look more like:
// does not compile
List<int> mapFoos(List<Foo> foos) {
return foos.map(Foo.v2);
}
But this fails to compile with the error:
The argument type '() → int' can't be assigned to the parameter type '(Foo) → int'
Is there some way to turn the member function into a lambda in a succinct way, so that
we can have something closer to the second example.
I could write
int applyV2(Foo f) {
return f.v2();
}
List<int> mapFoos(List<Foo> foos) {
return foos.map(applyV2);
}
but then I'd need to create that for each member function I want to map, which isn't really any better than using the lambda function.
If it makes any difference I'm using dart 1 due to "legacy reasons", if this has changed in recent versions I'd love to know that too.
No.
There is no shorter way to create a function which takes a Foo and calls its v2 method, than (f) => f.v2().
You can omit the Foo type on the parameter, because it can be inferred from the context (a List<X>.map<R> requires an R Function(X) as argument).
You cannot tear off Foo.v2 because v2 is an interface method, not a static method.
Just to elaborate on why Dart doesn't allow that, you can stop reading now if you just want to know what works:
Some languages allow you to tear off instance methods, so Foo.v2 becomes a function which expects its this object as an argument, in Dart a function of type int Function(Foo). Dart does not allow that. Probably for many different reasons, but most importantly because it cannot work. Dart types are interfaces, all class types can be implemented by another class without inheriting any implementation.
If you then tear off Foo.v2, you can call it with an instance of another class which implements Foo, but which won't necessarily find the private fields that Foo has, and which v2 could depend on.
Also, the tear-off would be covariant in its this-parameter.
Take SubFoo which extends Foo and has its own v2 method. If you do Foo foo = SubFoo(); var vtoo = foo.v2; then the static type of vtoo will be int Function(Foo), but the implementation from SubFoo will necessarily have runtime type int Function(SubFoo), which is not a subtype of the static type. That means it's unsound. The torn off function will have to do a run-time type check that its argument is actually a SubFoo, and throw if it's not. (So, that feature is not a good match for Dart.)

Adding the generic type to a comparable type in Dart

This is a followup question after reading this Q&A:
Generic Sorting function accepts T, but want to ensure T is comparable
I have a class like so:
class BinarySearchTree<E extends Comparable> { ... }
so I can create an instance like this:
final tree = BinarySearchTree<int>();
My question is about using Comparable vs Comparable<E>. When I do this:
class BinarySearchTree<E extends Comparable> { ... }
then the type defaults to E extends Comparable<dynamic>. I normally try to avoid dynamic, so in order to be more explicit about the type that is being compared, it seems like I should write it this:
class BinarySearchTree<E extends Comparable<E>> { ... }
But in that case I get an error here:
final tree = BinarySearchTree<int>();
// 'int' doesn't conform to the bound 'Comparable<int>' of the type parameter 'E'.
// Try using a type that is or is a subclass of 'Comparable<int>'.
This demonstrates my lack of understanding of generics. What am I missing?
In Dart, a class cannot implement 2 different concrete instances of a generic interface:
abstract class Foo<T> {}
// error: Foo can only be implemented once
class Bar implements Foo<String>, Foo<int> {}
num implements Comparable<num>, because it would be slightly absurd for the built-in number types to not be comparable. However, since int is a subtype of num (and therefore inherits Comparable<num>, it cannot have Comparable<int>.
This leads to the slightly weird consequence that int does not implement Comparable<int>.
The problem you're facing is that from the language's point of view, there are 2 types involved: the type of the elements being compared, and the type of the elements they are being compared to.
As such, your type will need 2 type parameters:
class Tree<T extends Comparable<S>, S> {
T get foo;
}
final intTree = Tree<int, num>();
final foo = intTree.foo; // returns an int
Admittedly, this isn't a super clean solution, but if you're using Dart 2.13 or higher, you can use typedefs to make it a bit nicer:
typedef IntTree = Tree<int, num>;
typedef RegularTree<T> = Tree<T, T>;
final intTree = IntTree();
final stringTree = RegularTree<String>();
intTree.foo // is an int
stringTree.foo // is a String
There is another option, which is to just drop some type safety and use Comparable<dynamic>, but personally I'd recommend against it. BTW, if you want to avoid accidentally missing type parameters you can disable implicit-dynamic as described here: https://dart.dev/guides/language/analysis-options#enabling-additional-type-checks
This will give an error any time the type dynamic is inferred from context without the programmer actually typing the word dynamic

is it possible to serial object to json in one function in dart

In Java, we can serial any object like this:
Object anyObj = new Object();
String json = JSON.tostring(anyObj);
but in Dart, we must define toJson method like this in every single Object:
import 'dart:convert';
String toJson() => json.encode(toMap());
and define toMap:
Map<String, dynamic> toMap() => {}
any simple way? Image if the system has 10000+ objects, are we write toJson function for every object? Is it possible to serial object to json like Java way in Dart?
Most Java libraries that provide serialization of arbitrary objects rely on runtime reflection to know what fields are present on an object (and their types, etc).
Runtime reflection is technically possible in Dart (using dart:mirrors) but the library is unstable and is not available on all platforms (notably runtime reflection is disabled in Flutter).
The idiomatic Dart way to do this is with code generation. In general, you add the required annotations/etc, then run flutter pub run build_runner build to use the build_runner package to generate extra code.
A couple of popular libraries are:
json_serializable is useful if you have a model class that you want to add toJson() and fromJson() methods to:
#JsonSerializable // marks the class for json code generation
class Dog {
final String name;
final int age;
Dog(this.name, this.age);
// boilerplate for generated implementations
Map<String, dynamic> toJson() => _$DogToJson(this);
factory Dog.fromJson(Map<String, dynamic> json) => _$DogFromJson(json);
}
built_value is a more all-encompassing approach. The main purpose of the library is to provide deep immutability for model classes, similar to Kotlin's data class. However, it also provides good serialization support out of the box. There is a fair amount of boilerplate, but it can definitely be worth it (especially if you use the vscode plugin to write it for you):
abstract class Dog extends Built<Dog, DogBuilder> {
Dog._();
factory Dog([void Function(DogBuilder) updates]) = _$Dog;
String get name;
int get age;
}
You can then use this code like:
final dog = Dog((b) {
b.name = 'name';
b.age = 123;
});
final helloDog = dog.rebuild((b) => b.name = 'hello');
This blog post goes through serialization in detail: https://medium.com/dartlang/darts-built-value-for-serialization-f5db9d0f4159#.h12y94wu7
Both libraries are maintained by Google

Dart passing types to functions fails

I have a map consisting of different types and strings:
const Map<Type, String> hiveTableNames = {
BreakTimeDto: "breaktime",
WorkTimeDto: "worktime"
};
And I want to loop through it because I want to call a function for each type which takes a type parameter:
Future<void> sendAll<T>(List item) async {
...
}
My attempt was to use the forEach-loop:
hiveTableNames.forEach((key, value) async {
final box = await Hive.openBox(value);
_helper.sendAll<key>(box.values.cast<key>().toList());
});
But the App throws an error: Error: 'key' isn*t a type.
Why is that? I declared the map to store types and from my understanding i pass these types in the function.
Dart separates actual types and objects of type Type. The latter are not types, and cannot be used as types, they're more like mirrors of types. A Type object can only really be used for two things: as tokens to use with dart:mirrors and comparing for equality (which isn't particularly useful except for very simple types).
The only things that can be used as type arguments to generic functions or classes are actual literal types or other type variables.
In your case, you have a Type object and wants to use the corresponding type as a type argument. That won't work, there is no way to go from a Type object to a real type.
That's a deliberate choice, it means that the compiler can see that if a type is never used as a type argument in the source code, then it will never be the type bound to a type parameter, so if you have foo<T>(T value) => ... then you know that T will never be Bar if Bar doesn't occur as a type argument, something<Bar>(), anywhere in the program.
In your case, what you can do is to keep the type around as a type by using a more complicated key object.
Perhaps:
class MyType<T> {
const MyType();
R use<R>(R Function<X>() action) => action<T>();
int get hashCode => T.hashCode;
bool operator==(Object other) => other is MyType && other.use(<S>() => T == S);
}
This allows you to store the type as a type:
final Map<MyType, String> hiveTableNames = {
const MyType<BreakTimeDto>(): "breaktime",
const MyType<WorkTimeDto>(): "worktime"
};
(I'm not making the map const because const maps must not have keys which override operator==).
Then you can use it as:
hiveTableNames.forEach((key, value) async {
final box = await Hive.openBox(value);
key.use(<K>() =>
_helper.sendAll<K>([for (var v in box.values) v as K]);
}
(If all you are using your map for is iterating the key/value pairs, then it's really just a list of pairs, not a map, so I assume you are using it for lookups, which is why MyType override operator==).
In general, you should avoid using Type objects for anything, they're very rarely the right tool for any job.

How do I dispatch a constructor on a class in Dart?

I previously had the following code, it works fine. (note that Card, SearchResults, Quiz all extend Persistable, and Persistable contains the constructor .fromMap.
Persistable fromString(String value){
Map<String, dynamic> m = parse(value);
switch(m['type']){
case 'card':
return new Card.fromMap(m);
case 'searchresults':
return new SearchResults.fromMap(m);
case 'quiz':
return new Quiz.fromMap(m);
}
}
It was a bit wordy, so I thought I would break it down into two parts. I first have this:
static final Map<String, Persistable> lookup =
{'card': Card,
'searchresults': SearchResults,
'quiz': Quiz };
Seems reasonable, but then when I try to redefine the method, I get confused.
Persistable fromString(String value){
Map<String, dynamic> m = parse(value);
String type = m['type'];
Persistable p = lookup[type];
... Confused, this can't be right
... ultimately want to "return new p.fromMap(m)";
}
Persistable p really means a instance of class Persistable. How do I type my lookup map so that its values are of the class Persistable, so that I can call their .fromMap constructors?
First of all I think your initial approach is perfectly valid and should not be cast away owing simply to its verbosity.
I believe alternative approaches introduce additional complexity and are justified only if you are really in need of dynamic dispatch. (For example if you write library for persistency and you wish to add ability to register arbitrary class for persistency for clients of library)
If dynamic dispatch is a must for you I believe there is two main possibility:
- Reflection API. Recently reflection library got sync API, so this way is now much more affordable then before. I believe there always will be some cost incurred by reflection anyway.
- Use core DART functionality.
With the second approach you may use some sort of trick to imitate constructor call dynamically.
For instance you may store in map not Type variable but function which returns instance of required class:
So your code may look something like
static final Map<String, Function> lookup = new Map<String, Function>
static void registerClass(String className, factory) {
lookup[className] = factory;
}
static Persistable getInstance(String className, Map map){
return lookup[className](map);
}
And on client side:
....
registerClass('quiz', (map)=> new Quiz.fromMap(map));
registerClass('card', (map)=> new Card.fromMap(map));
(Attention - I did not test this)
You may look for working sample code for that approach in https://github.com/vadimtsushko/objectory

Resources