How would you translate a Map to and object for dart - dart

Lets say I want to refactor my code so it's easier to read and I have an object property that is type of Map<String,AnotherObject or dynamic> what is the best way to convert this property to another object? When it is a map I can call the relevant object using its String key. If it becomes another object how would I call the one I want?
for example:
class A1{
Map<String,B1> property;
}
to:
class A1{
List<B2> property;
}
class B2{
String key;
B1 property;
}
In the example above in order to get the property I want I would have to filter the list where key = keyIwant, while if it is a map I can just call map[key]. Is there any effective way to convert a map to an object? Dart is the technology I use.

I suppose you're trying to make your code more maintainable by replacing your current Map with something else, which you refer to as object.
I also suppose that by object you mean Dart classes with typed fields.
If you want to continue to be able to find "objects" by their String names, you cannot avoid using a Map.
If the "keys" are all known at compile-time (ie. before your program actually runs) then you can used typed objects, which is what you should prefer as it makes reasoning and organizing code much easier.
Let's say you know that your Map will only ever have keys a and b with types A and B, respectively. Then you can replace your Map easily:
class A {}
class B {}
class MyClass {
final A a;
final B b;
MyClass(this.a, this.b);
}
Simple.
If some "keys" may not be present, just turn them into nullable values:
class A {}
class B {}
class MyClass {
final A? a;
final B? b;
// passing a or b is now optional!
MyClass({this.a, this.b});
}
If you don't know what the keys will be at all, then there's no way around using a Map. That's what they are for.
With Dart support for dynamic typing, you could "assume" certain keys will have certain types, though. So, while this is normally bad for code maintenance due to the impossibility to analyze this before the program runs (ie. it may crash at runtime), you could do something like this:
class Foo {
final String a;
Foo(this.a);
String toString() => 'Foo($a)';
}
class Bar {
final String a;
Bar(this.a);
String toString() => 'Bar($a)';
}
// example usage
void main() {
Map<String, dynamic> map = {'foo': Foo('a foo')};
Foo foo = map['foo'];
print(foo); // ok!
Bar? bar = map['bar'];
print(bar); // null
}
Hopefully this helps clarify when you should use an "object" and when you need to use a Map.

Related

How can I access static members in a generic context?

I need a workaround or idiomatic way to access the static members defined in some type from a generic context.
Example:
enum E { first, second, third }
// no direct syntax to constrain to enum types
class EnumKeyList<TEnum> {
List<Object> _values;
// unable to access static member
EnumKeyList() : _values = List.filled(TEnum.values.length, Object());
// unable to access instance member
Object operator [](TEnum entry) => _values[entry.index];
}
Usage:
final list = EnumKeyList<E>(); // E.values.length would provide implicit fixed-size list instantiation
list[E.first] = 5; // can use enumeration entries as keys
I want to avoid the overhead of Map (hashing and additional memory). The real use case must index into the list in tight loops.
Having a fixed set of named keys is a useful requirement, but the example EnumKeyList should work with any generic type argument that provides an enumeration like interface.
Using enumerations provides the shortest way to declare valid 0-indexed keys and the count of the amount of entries through an enumeration's static values member.
Swift enumerations and protocols allow for static members. C# has constraints for enumeration types. C++ generics dwarf everything. Is there a simple way to achieve this in Dart?
I realize that I can declare my own class instead of an enumeration, but then I lose the implicitly generated members (having to manually assign a value to each constant in the class (bad for maintenance)) and I still can't provide access to a static member from the generic context.
See here for examples of how unmaintainable this is:
abstract class Enum {
final int rawValue;
const Enum(this.rawValue) : assert(rawValue >= 0);
// don't bother with a static 'values' member
}
class E extends Enum {
const E(int rawValue) : super(rawValue);
static const first = E(0);
static const second = E(1);
static const third = E(1); // repeated values
static const List<E> values = <E>[first, second]; // missed one
}
You cannot access static members through type variables.
Dart static members are really just declared in the namespace of the corresponding class/mixin/extension declaration, they are not part of the type. Type variables hold types, not declarations.
There is no idiomatic workaround.
You have to figure out which operations you need your class to support, then you can introduce a strategy object representing the class, and pass that to the function instead of (or alongside) the type argument.
In this case, you probably want the EnumKeyList constructor to take the list of values as an argument, so:
EnumKeyList(List<T> values) : _values = List.unmodifiable(values);
The workaround, in general, is to pass the values you'd want to read from a static member directly to the function needing them, along with the type.
You can't access them using the type alone.
The "cannot access index" problem could be fixed by the language adding an interface to all enums, like abstract class Enum { int get index; } and make all enum classes implement that interface.
There is no easy way to allow access to the values knowing only the type.
It might be possible to do something magical in the compiler and platform libraries, but it won't extend to user-written enums like this, and no viable way to emulate it.

Dart multiple upper bounds

I need to implement a solution using generics that implements 3 interfaces, but as far as I can tell, generics in dart only supports 1 upper bound?
I have a model that looks like this:
abstract class Category implements Built<Category, CategoryBuilder>, Identifiable, Mapable {
...
}
The contents of the 3 interfaces is not really relevant, and what I'm trying to do, is construct a class that can process this in generic form.
What I want is something like this:
abstract class BaseDB<T extends Built<T, R> & Identifiable & Mapable, R extends Builder<T, R>> {
process(T entity) {
print(entity.id); // From Identifiable
entity.toMap(); // From Mapable
// ... etc
}
}
I know this is possible in both Typescript and Java, but I'm fairly new at Dart. Anyone know?
This is not possible in Dart. You can only put one bound on a type variable.
The bound of a Dart type variable is used to check which operations you can do on an object of the type parameter type. Example:
String something<T extends num>(T value) {
return value.abs().toString();
}
You are allowed to call abs() on value because we know that all instances of value are numbers, and num has an abs method.
If you can write <T extends Foo & Bar>, then there is no simple type in the Dart type system that can describe objects of type T. Dart does not have intersection types (the intersection type Foo & Bar would be a supertype of all types that are subtypes of both Foo and Bar, and a subtype of both Foo and Bar).
If Foo declares Baz method(), Bar declares Qux method(), and value has type T, what is the type of value.method()?
(It would either be disallowed, or the type would be Baz & Qux). This shows that allowing & in type variable bounds leaks intersection types into the remaining type system, and since Dart does not have intersection types, it also does not have multiple bounds on type variables.
When you declare a class, FooBar, implementing both Foo and Bar, you have the same issue: You need to figure out what method returns. However, the language requires you to write that solution into your class, to find some valid return type for FooBar.method, because otherwise the FooBar class declaration is not valid. It requires a user to find a solution to "find a subclass of both Baz and Qux".

When should final fields, factory constructors or private fields with getters be used in dart?

If you can figure out how to rename this question, I'm open for suggestions.
In the Dart language, one can write a class with final fields. These are fields that can only be set before the constructor body runs. That can be on declaration (usually for static constants inside a class), in an initialiser list syntax when declaring the constructor or using the this.field shorthand:
class NumBox{
final num value;
NumBox(this.value);
}
Let's say I actually needed to do some processing on instance creation and can't just initialise the field before the constructor. I can switch to using a private non-final field with a getter:
class NumBox{
num _value;
NumBox(num v) {
_value = someComplexOperation(v);
}
num get value => _value;
}
Or I can get a similar behavior using a factory constructor:
class NumBox{
final num value;
factory NumBox(num v) {
return new NumBox._internal(someComplexOperation(v));
};
NumBox._internal(this.value);
}
I hit a similar bump when I tried learning Dart a few years back and now that I have more baggage, I still don't know. What's the smarter way to do this?
A factory constructor is a good way, it allows to pre-calculate without limitations any values that you then pass to a normal constructor to forward to final fields.
An alternative way is initializer list which is executed before the constructor body and therefore allows to initializer final fields:
class NumBox{
final num value;
NumBox(num v) : value = someComplexOperation(v)
}
In the initializer list you are not allowed to read this because the instance isn't fully initialized yet.
DartPad example
You should design your API with your user in mind, then implement it in whatever way is simpler and more maintainable to you. This question is about the latter part.
Making fields final is great when it's possible, and when it isn't, making them private with a public getter is a good alternative. It's your choice what to do, because it's you who is going to maintain your class, nobody else should need to look behind the public API.
If you need a complex computation, Günther Zöchbauer's suggestion is the first to turn to: Use a helper function. In some cases, you can even do it inline
class MyThing {
final x;
MyThing(args) : x = (() { complex code on args; return result;} ());
}
It gets ugly quickly, though, so having it as a static helper function is usually better.
If your complex computation doesn't match this, which ususally means that there is more than one field being initialized with related values, then you need a place to store an intermediate value and use it more than once when initializing the object.
A factory constructor is the easy approach, you can compute everything you need and then call the private generative constructore at the end. The only "problem" is that by not exposing a generative constructor, you prevent other people from extending your class. I quoted "problem" because that's not necessarily a bad thing - allowing people to extend the class is a contract which puts restrictions on what you can do with the class.
I tend to favor public factory constructors with private generative constructors even when it's not needed for any practical reason, just to disable class extension.
class MyClass {
const factory MyClass(args) = MyClass._; // Can be const, if you want it.
const MyClass._(args) : ... init .. args ...;
}
If you need a generative constructor, you can use a forwarding generative constructor to introduce an intermediate variable with the computed value:
class MyClass {
final This x;
final That y;
MyClass(args) : this._(args, _complexComputation(args));
MyClass._(args, extra) : x = extra.theThis, y = extra.theThat, ...;
}
All in all, there is no strict rule. If you prefer final fields, you can do extra work to make them final, or you can just hide the mutability behind a getter - it's an implementation and maintainability choice, and you're the one maintaining the code.
As long as you keep the abstraction clean, and keeps track of what you have promised users (generative constructor? const constructor?) so you won't break that, you can change the implementation at any time.

Dart Map with String key, compare with ignore case

Does the Map class in Dart have a way to ignore case if the key is a string?
Eg.
var map = new Map<String, int>(/*MyComparerThatIgnoresCase*/);
map["MyKey"] = 42;
var shouldBe42 = map["mykey"];
In C# the Dictionary constructor takes a comparer like the comment above. What is the canonical way to do this in Dart?
Maps in Dart have an internal method that compares keys for equality. So far as I know, you can't change this for the default Map class. However, you can use the very similar core LinkedHashMap class, which not only allows, but requires that you specify a key equality method. You can check out more about LinkedHashMaps at https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart:collection.LinkedHashMap
LinkedHashMap<String, String> map = new LinkedHashMap(
(a, b) => a.toLowerCase() == b.toLowerCase(),
(key) => key.toLowerCase().hashCode
);
map['Foo'] = 'bar';
print(map['foo']); //bar
The way to create a HashMap with a custom equals function (and corresponding custom hashCode function) is to use the optional parameters on the HashMap constructor:
new HashMap<String,Whatever>(equals: (a, b) => a.toUpperCase() == b.toUpperCase(),
hashCode: (a) => a.toUpperCase().hashCode);
I really, really recommend finding a way to not do the toUpperCase on every operation!
You can also do this using package:collection's CanonicalizedMap class. This class is explicitly designed to support maps with "canonical" versions of keys, and is slightly more efficient than passing a custom equality and hash code method to a normal Map.
Dart has a nifty
CaseInsensitiveEquality().equals(String a, String b)
in their
import 'package:collection/collection.dart';
It returns a bool and worked great for me when I was translating strings back to an enum. You do have to run dart pub add collection at the command line to install the package.

Flash / ActionScript - application design question

Could someone share the way how this should be designed:
Let's say I have some data model, which is built using Entries.
Basically, I have one abstract class Entry (or interface IEntry - that's not so important for the case) and have several implementations of this class - MovieEntry, SoundEntry, FoodEntry, whatever...
Each of those is a wrapper for some data (url, description, number of calories, etc) and this data is grouped together in each corresponding class.
Now - if I wish to display the data for the entries on the screen (let's say movie posters and annotations for the MovieEntry) - how should I design that?
Obviously I could provide another interface / abstract class and call it DrawableEntry (and it would inherit Sprite) and then build a bunch of classes like DrawableMovieEntry and DrawableSoundEntry which could look like:
class DrawableMovieEntry extends DrawableEntry { // which also extends 'Sprite'
private movieEntry:MovieEntry;
public override function draw(backend:*) {
// Draw everything using the 'movieEntry' reference
// stored.
};
But this seems to be kind of an overkill for a small application.
Another approach is to make the MovieEntry, SoundEntry, ... extend sprite and provide the drawing implementations themselves - but this is obviously bad, because data becomes strongly coupled with it's visualization routines.
So - how should this be done? Maybe MVC approach has something to offer for this case?
Your use case seems to be the perfect example for the Strategy pattern or the Command pattern.
Strategy being the simpler one, here is an example:
Create an IDrawStrategy interface like this:
package {
public interface IDrawStrategy {
function draw( obj:Object ) : void;
}
}
Implement several DrawStrategies:
package {
public class SoundEntryDrawStrategy implements IDrawStrategy {
public function draw (obj:Object) : void {
// cast obj to SoundEntry and do all the drawing necessary,
// or fail if obj is null or not a SoundEntry
}
}
}
package {
public class MovieEntryDrawStrategy implements IDrawStrategy {
public function draw (obj:Object) : void {
// cast obj to MovieEntry and do all the drawing necessary
// or fail if obj is null or not a MovieEntry
}
}
}
etc.
Then add a new member to your base Entry class:
private var _drawStrategy:IDrawStrategy;
and create a setter:
public function set drawStrategy ( strat:IDrawStrategy ) : void {
_drawStrategy = strat;
}
and a draw method:
public function draw () : void {
_drawStrategy.draw( this );
}
You can now assign and execute the fitting strategies to each of your entries:
var mov:MovieEntry = new MovieEntry();
mov.drawStrategy = new MovieEntryDrawStrategy();
mov.draw();
BTW the Sprite you draw the information in can, but doesn't have to, be a member of the DrawStrategy class, but if you wanted to add a clear() method later, it would be better to keep a reference ;).
The entries you build your data model with are, among others, referred to as value objects (VO) or data value objects (DVO). To answer your last question first, I'd never have a VO extend something other than a base VO class, so don't extend Sprite, you'll regret it later.
Over to the hierarchy. You're extending the abstract class Entry to create concrete subclasses, but since you also mention a possible interface, I'm not sure you should use extend. Only use a common base class if your value objects actually share common properties. If every entry has a title property, fine, put that one in Entry and subclass it. If your abstract would be empty, I'd recommend using a marker (=empty) interface instead.
I have a common marker interface for value objects, that have more specific subinterfaces to add features like xml parsing or composition. Once you start using interfaces for this, it's easy to enhance.
Then the displaying. There's not one right answer to this one, the more because your example is still pretty broad. But I'd pass the VO to the object as a whole, through a method that states that it's going to store the VO and redraw itself.
interface IEntryDisplay {
redrawWithEntry(entry:IEntry):void;
}
Use the IEntry interface to pass the object as a whole. In your implementation, use an if cascade with is Type conditions to do the drawing.
public function redrawWithEntry(entry:IEntry):void {
this.entry = entry;
if (entry is MovieEntry) {
title.text = MovieEntry(entry).title;
} else if (entry is SoundEntry) {
title.text = "(Sound) "+SoundEntry(entry).fileName;
}
}
If you decide to use a base class for the Entry hierarchy, use that one instead of the interface. You want your methods asking for the value object type that is as close to the needed object as neccessary.
Because you store the entry in your display class, it's easy to pass along some time later when you click the display or when you want to have it do something else.
Does this help?

Resources