Can a method in Dart have a semicolon after the closing brace? - dart

Hi i am new to the Dart programming language, i have been looking at this code for local persistence for a journal app. My confusion came when i came across this:
Map<String, dynamic> toJson() => {
"journals": List<dynamic>.from(journal.map((x) => x.toJson())),
};
What confuses me is what does this translate to, i think it translates to the following:
Map<String, dynamic> toJson() {{
"journals": List<dynamic>.from(journal.map((x) => x.toJson())),
};}
Which is wrong (because Vs Code is shouting # me), i also thought toJson() is simply a Map variable but again that is wrong,
now if it is a method that means its return type is Map<String, dynamic>, but then where is the return statement in the body of the function?
,my other question is what does it really translate to if we are to remove the short hand, and help me understand what kind of function ends with a semi colon like that, please help a newbie

It "translates" (as in: means the same thing as)
Map<String, dynamic> toJson() {
return {
"journals": List<dynamic>.from(journal.map((x) => x.toJson())),
};
}
The function returns a single value, which is a Map literal.
Map literals have the form {key: value, ..., key: value}.
This can be confusing to people coming from modern JavaScript, because JavaScript introduced a function shorthand where (x) => { ... } is shorthand for function(x) { ... }. The body of a JavaScript => is a statement block. The content of a Dart => is a single expression, the value of which is returned.

Related

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 to get a property by this name in String?

I want to access to a property by the name si string format.
If I have a class like that:
class PrefsState {
String a;
PrefsState({
this.a,
})
How can I do something like that:
PrefsState test= PrefsState(a: "it is a test");
String key = "a";
print(test[key]);
Of course is not working. There is a way to do that in Dart ?
Unfortunately, you cannot use reflection/mirrors in flutter.
What you can do, which is tedious, is use maps.
class PrefsState {
String a;
const PrefsState({ this.a, });
dynamic getProp(String key) => <String, dynamic>{
'a' : a,
}[key];
}
It's probably better to build the map in the constructor, but if you want const constructors then you'll have to settle for this. Likely won't make much of a difference unless you have a million parameters anyway. Then you use it like so:
PrefsState test= PrefsState(a: "it is a test");
String key = "a";
print(test.getProp(key));
I don't think there is a less cumbersome way of doing this, but would love to be proven wrong :-)
You can do it with mirrors, but mirrors don't work in dart2js or flutter. You can use code builders to get at this, but the real question is what is your need for this?

Print detailed structure / type information of a variable's value

I wonder, if a dart or flutter method exists, which returns complete type information about the structure of a variable's value as a string.
E.g., if some print( someValue.toString() ); emits this
{"user":"userName","state":"valid"}
I don't know if it is a Map or a String.
But how do I get a string, which describes a variable's value / structure?
Something, that's like PHP's print_r(), which print stuff like this:
Array
(
[a] => Apfel
[b] => Banane
[c] => Array
(
[0] => x
[1] => y
[2] => z
)
)
There is nothing like print_r() available natively in Dart.
However, it would be possible to use the following functionalities to build e.g. a function like print_r() from PHP.
You can evaluate the type of someValue using runtimeType.
String someValueType = someValue.runtimeType.toString();
String someValueString = someValue.toString();
If you want to compare, you can also use is. More on that here.
Dart is a strongly typed language, which means that you could also enforce types (List a; String b), which makes a function like print_r() redundant for Dart.
If it is about server-side code you can use reflection to create a function that produces such an output for every value.
If it is about your own classes, you can implement toString() to make the objects render themselves this way when they are printed
class Person {
Foo(this.firstName, this.lastName);
String firstName;
String lastName;
#override
String toString() => '''
firstName: $firstName
lastName: $lastName
''';
}
print(new Person('John', 'Doe'));
Best way to do is
print(”$someValue“);
It will return a structured string which similar to JSON.

How to handle implicit cast warnings of strong mode analysis?

A common thing I do in my web application is request a resource from the server and handle it as a Map in dart.
import 'dart:convert';
const String sampleJSON = '''
{
"member": {
"meaningOfLife": 42
}
}
''';
Map<String, dynamic> getResource() {
// do some magic
return JSON.decode(sampleJSON);
}
I live with the assumption that all keys in a JSON decoded Map will be Strings but obviously I have no clue of the value's type. In checked mode this worked fairly well.
Analysis in strong mode to the code above will tell me: Unsound implicit cast from dynamic to Map<String, dynamic>
Question:
What is a good strategy to handle such cast warnings?
Questionable options 1:
Map getResource() {
// do some magic
return JSON.decode(sampleJSON);
}
Later this could be a problem: Iterable<String> keys = getResource().keys will give a warning.
Questionable option 2:
Map<String, dynamic> getResource() {
// do some magic
return new Map<String, dynamic>.from(JSON.decode(sampleJSON));
}
Does it not degrade performance much? And I will still get a warning for Map<String, dynamic> meaning = getResource()["member"];
Thanks for the advice.
If you know the type then just make it explicit
return JSON.decode(sampleJSON) as Map<String,dynamic>;
The Flutter team forbids the use of as because it introduces a runtime check and has performance implications. If it is relevant, depends on your requirements.
Alternatively, you can just silence the warning (might not yet work in your Dart version)
// ignore: STRONG_MODE_DOWN_CAST_COMPOSITE
return JSON.decode(sampleJSON);
See also Suppress hint about use of protected member

What's the equivalent to not using params with Expression<Func<>>[]?

I have some code in a repository base class for Entity Framework that eager loads Navigation properties:
public virtual List<T> Find(Func<T, bool> where, params Expression<Func<T, object>>[] navigationProperties)
{
//blah biddy blah blah
}
Then when calling the above method:
var beers = BeerRepository.Find(x => x.Type == "IPA", a => a.Ingredients, b => b.Sizes, c => c.Hangovers);
It works great. I know that using "params" provides a great magic shortcut when calling the method and I've seen some SIMPLE examples of what would be needed without it.
But, I'm having trouble figuring out how to call the method above when I remove params from the signature.
Any thoughts?
A generic method is a method template. If you supply a type argument, it becomes a concrete, typed, method. Your method (without params)...
public virtual List<T> Find<T>(Func<T, bool> where,
Expression<Func<T, object>>[] navigationProperties)
...in BeerRepository will turn into something like...
public virtual List<Beer> Find(Func<Beer, bool> where,
Expression<Func<Beer, object>>[] navigationProperties)
...which clearly shows you have to provide a Expression<Func<Beer, object>>[] array. It takes a bit more clunky code to build that, because you can't take advantage of type inference:
var navProps = new Expression<Func<Beer, object>>[]
{
a => a.Ingredients,
a => a.Sizes,
a => a.Hangovers
});
Not sure I understand your question.
You can just call
beerRepository.Find((x => x.Type == "IPA")
And then inside Find() you'll see that the navigationProperties array will be empty.

Resources