Case expressions must be constant in Dart [duplicate] - flutter

Let's say I have a ColorPalette class that looks like the following:
class ColorPalette {
static const Map<int, Color> gray = {
400: Color(0xFFDDDDDD),
500: Color(0xFFEEEEEE),
// ...
};
// Primary colors in separate variable
static const Color primaryBlue = Color(0xFF0000FF);
// ...
}
And if I were to assign a color value of the map to a variable that expects a const value:
class SomeOtherClass {
static const Map<String, Color> stateColor = {
// Error
'pressed': ColorPalette.gray[500],
}
}
Complains that "Const variables must be initialized with a constant value."
But this works fine:
...
'pressed': ColorPalette.primaryBlue,
...
Plus when assigning map, doing 500: const Color(...) or static const Map<int, Color> gray = const {...} didn't work either.
So I suspect that this is throwing error probably because compiler doesn't evaluate all entries in the map during compile time and therefore, the value being accessed with the given key can be only known during runtime?
Is there any workaround to assign value from a map to a variable that expects a const value?

There is no workaround.
An expression of the form e1[e2] cannot be a constant. The [] operator is a method (all user-definable operators are), and you cannot call a method at compile time except for a very small number of operations on known system types. Map lookup, even on constant maps, is not one of those exceptions.
The reason ColorPalette.primaryBlue works is that it directly references a const variable.

Related

Dart / Flutter nested classes static access

I'm trying to use a version of nested classes to make a tree of constant strings throughout my app in Flutter. I'd like them to be nested in order to find const strings quickly as the app grows, but still have the additional 'speed' of using the const keyword for Text() widgets.
However, I'm having a hard time trying to use them in const Text() widgets.
Here's a sample:
class Strings {
static const String ok = 'OK';
static TechnicianStrings technicianStrings = TechnicianStrings();
}
class TechnicianStrings {
TechnicianStrings();
final String createTech = 'Create Technician';
final String technician = 'Technician';
}
Throughout the app, I'd like to use these constant Strings as so:
const Text(Strings.ok), // <-- this works
const Text(Strings.technicianStrings.technician), //<-- only works without 'const'
const Text(Strings.technicianStrings.createTech), //<-- only works without 'const'
However, I get an error of "Arguments of a constant creation must be constant expressions" when I use the const keyword for the text widgets.
I've tried to use varying "const and static" names for the members of TechnicianStrings, and I get errors such as "invalid Constant" for the text widget. I also defined TechnicianStrings as static const, and got an error of 'Constant variables must be initialized with a constant value' for the line:
static const TechnicianStrings technicianStrings = TechnicianStrings();
Is there a way to use such a nested class structure hand in hand with const Text() widgets?
You need a constant constructor in TechnicianStrings.
class Strings {
static const String ok = 'OK';
static const TechnicianStrings technicianStrings = TechnicianStrings();
}
class TechnicianStrings {
const TechnicianStrings(); // <---
final String createTech = 'Create Technician';
final String technician = 'Technician';
}

Difference between static and const variable in Dart

Check these two examples:
static const inside of class:
class SessionStorage {
static const String _keySessionExist = 'storage.key';
}
Just a const outside of the class:
const String _keySessionExist = 'storage.key';
class SessionStorage {
}
Is there any difference or implications between having a static const variable inside of a class or just having it declared as const outside of it in Dart?
Maybe the compiled code changes?
Which one is more performant?
Which one should we follow if the variable is private to the file?
The declaration for cons must be using const. You have to declare it as static const rather than just const.
static, final, and const mean entirely distinct things in Dart:
static means a member is available on the class itself instead of on instances of the class. That's all it means, and it isn't used for anything else. static modifies members.
final means single-assignment: a final variable or field must have an initializer. Once assigned a value, a final variable's value cannot be changed. final modifies variables.
const has a meaning that's a bit more complex and subtle in Dart. const modifies values. You can use it when creating collections, like const [1, 2, 3], and when constructing objects (instead of new) like const Point(2, 3). Here, const means that the object's entire deep state can be determined entirely at compile time and that the object will be frozen and completely immutable.
Const objects have a couple of interesting properties and restrictions:
They must be created from data that can be calculated at compile time. A const object does not have access to anything you would need to calculate at runtime. 1 + 2 is a valid const expression, but new DateTime.now() is not.
They are deeply, transitively immutable. If you have a final field containing a collection, that collection can still be mutable. If you have a const collection, everything in it must also be const, recursively.
They are canonicalized. This is sort of like string interning: for any given const value, a single const object will be created and re-used no matter how many times the const expression(s) are evaluated. In other words:
getConst() => const [1, 2];
main() {
var a = getConst();
var b = getConst();
print(a === b); // true
}
I think Dart does a pretty good job of keeping the semantics and the keywords nicely clear and distinct. (There was a time where const was used both for const and final. It was confusing.) The only downside is that when you want to indicate a member that is single-assignment and on the class itself, you have to use both keywords: static final.
Also:
I suggest you to have a look at this question
What is the difference between the "const" and "final" keywords in Dart?
Is there any difference or implications between having a static const variable inside of a class or just having it declared as const outside of it in Dart?
The obvious difference is that the static version must be referenced with the class name. Other than the change in name resolution, the should be the same.
Maybe the compiled code changes?
Which one is more performant?
They're both compile-time constants. There shouldn't be any difference.
Which one should we follow if the variable is private to the file?
If you want something that's private to a Dart library (which usually means the file), then prefix it with _. It doesn't matter whether it's global or static.

In dart, how to assign a value from a const Map to a const variable?

Let's say I have a ColorPalette class that looks like the following:
class ColorPalette {
static const Map<int, Color> gray = {
400: Color(0xFFDDDDDD),
500: Color(0xFFEEEEEE),
// ...
};
// Primary colors in separate variable
static const Color primaryBlue = Color(0xFF0000FF);
// ...
}
And if I were to assign a color value of the map to a variable that expects a const value:
class SomeOtherClass {
static const Map<String, Color> stateColor = {
// Error
'pressed': ColorPalette.gray[500],
}
}
Complains that "Const variables must be initialized with a constant value."
But this works fine:
...
'pressed': ColorPalette.primaryBlue,
...
Plus when assigning map, doing 500: const Color(...) or static const Map<int, Color> gray = const {...} didn't work either.
So I suspect that this is throwing error probably because compiler doesn't evaluate all entries in the map during compile time and therefore, the value being accessed with the given key can be only known during runtime?
Is there any workaround to assign value from a map to a variable that expects a const value?
There is no workaround.
An expression of the form e1[e2] cannot be a constant. The [] operator is a method (all user-definable operators are), and you cannot call a method at compile time except for a very small number of operations on known system types. Map lookup, even on constant maps, is not one of those exceptions.
The reason ColorPalette.primaryBlue works is that it directly references a const variable.

Dart Class with ":" vs Dart Class without [duplicate]

I have a class that I am creating that looks like this:
class Movie {
final String title, posterPath, overview;
Movie(this.title, this.posterPath, this.overview);
Movie.fromJson(Map json) {
title = json["title"];
posterPath = json["poster_path"];
overview = json['overview';
}
}
I am getting a warning that says that "The final variables 'overview', 'posterPath', & '1' more must be initialized. There are also warnings around each variable saying 'title' can't be used as a setter because it is final.
When I write the constructor using this syntax, the warnings go away:
Movie.fromJson(Map json)
: title = json["title"],
posterPath = json["poster_path"],
overview = json['overview'];
What exactly is going on here?
Dart objects must be fully initialized before anyone gets a reference to the new object. Since the body of a constructor can access this, the object needs to be initialized before entering the constructor body.
To do that, generative Dart constructors have an initializer list, looking similiar to C++, where you can initialize fields, including final fields, but you cannot access the object itself yet. The syntax:
Movie.fromJson(Map json)
: title = json["title"],
posterPath = json["poster_path"],
overview = json['overview'];
uses an initializer list (the list of assignments after the :) to initialize the final instance variables title, posterPath and overview.
The first constructor uses an "initializing formal" this.title to directly put the parameter into the field.
The constructor
Movie(this.title, this.posterPath, this.overview);
is effectively a shorthand for:
Movie(String title, String posterPath, String overview)
: this.title = title, this.posterPath = posterPath, this.overview = overview;
Your constructor can combine all of these and a body:
Movie(this.title, this.posterPath, String overview)
: this.overview = overview ?? "Default Overview!" {
if (title == null) throw ArgumentError.notNull("title");
}
(A const constructor cannot have a body, but it can have an initializer list with some restrictions on the allowed expressions to ensure that they can be evaluated at compile-time).
Dart separates properties initialization from the constructor body.
A constructor has 3 parts :
the name/parameters definition
properties initialization/super call/asserts
A body, similar to a function immediately run on construction
Both the initialization and body parts are optional.
final variables must be initialized on the first 2 parts. They cannot be initialized inside the body.
A full constructor will look like the following :
MyClass(int value)
: assert(value > 0),
property = value,
super();
{
print("Hello World");
}
The main purpose of this initializer part is for body-less constructors which allows const constructors, a dart specific feature. See How does the const constructor actually work? for more details on these.
I just found some documentation around this, & it seams that the second version with the : is what's called the "initializer list" which allows you to initialize instance variables before the constructor body runs.
There is more detail around this in the documentation here.

Getter using references and returning a constant variable

I have the following question: I define a class containing a private vector of (my) objects - i.e.:
vector<myOtherClass> myVector;
Then I would like to define a getter method which should not copy all objects saved in the vector. Thus I am always using references:
vector<myOtherClass> &getMyVector() const {
return (myVector);
}
The “const” means that I can only read the member variables in this method. But what should I do if I want that the returning variable is a constant - in particular what difference is between the three following possibilities (sometimes, the compiler allows me only to use one of them):
const vector<myOtherClass> &getMyVector() const {
return (myVector);
}
,
vector<myOtherClass> const &getMyVector() const {
return (myVector);
}
and
const vector<myOtherClass> const &getMyVector() const {
return (myVector);
}