Dart: Is there a disadvantage to using const constructor? - flutter

There is an analyzer/lint check to warn me when it is possible to use a const constructor: https://dart-lang.github.io/linter/lints/prefer_const_constructors.html
(ie. using final a = const A(); instead of final a = A();)
I think to understand the advantages (there will only ever be one instance with the same constant values for a const constructor). But why isn't this the default? Since dart 2 the new can be omitted, so why didn't they change the definition of creating a new instance which can be created const simply as const instead of new? I assume there must be some disadvantage to having everything const?
(for example in a constant context like const [A()] it is actually the same as const [const A()], so why not everywhere)?

so why didn't they change the definition of creating a new instance which can be created const simply as const instead of new?
If you mean why doesn't final a = A(); automatically assume const A() if A has a const constructor:
Sometimes it is automatic:
const a = A();
in which case A's constructor is being invoked in a const context and doesn't need an extra const qualifier on the right-hand-side.
An explicit const expresses intent. For example, suppose you had:
final a = A(B());
where A and B have const constructors. Later, somebody makes a change:
final a = A(C());
where C does not have a const constructor. If const were automatic, then you would have no idea that a is no longer const. Maybe that's okay, but it also could suddenly have a negative impact on your application's performance, and without an explicit const qualifier, the impact of a local change could have a much wider scope than expected. (That said, explicit const qualifiers and automatically adding them aren't mutually exclusive.)
const can have downsides. const creates compile-time constants. If you have:
final a1 = A();
final a2 = A();
identical(a1, a2) is not true. If const A() were implicit, then identical(a1, a2) would be true, and maybe that's not a property that the code intended to have.
Compile-time constants live forever. The whole point is to have an object that can be reused instead of re-constructing it. The flipside is that won't be destroyed.

Related

Case expressions must be constant in Dart [duplicate]

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.

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.

Why const keyword is used after assignment operator in dart?

I am learning Flutter(Mostly from Youtube) & while learning it I have seen many instructor have used a statement like this,
final SomeClass someVariable = const SomeClass(withSomeValue);
What bothers me that why do we need to use const keyword after the assignment operator there since we already made it a final & I already know that final keyword is used to define a constant variable. So what does const signifies here?
It's a memory optimization possible with immutable objects.
const instances are shared:
final a = const Whatever();
final b = const Whatever();
print(identical(a, b)); // true
In this snippet, both a and b share the same object instance, so it is allocated only once.
Here, the object allocation, takes place just once, so it is good for performance.
final Test test = const Test();
final Test test2 = const Test();
Here it takes place twice.
final Test test = Test();
final Test test2 = Test();

Const member function vs const return type

In D I can specify const functions, like in c++:
struct Person {
string name;
// these two are the same?
const string getConstName() { return name; }
string getConstName2() const { return name; }
}
It seems that the above two are the same meaning. Is it true?
If so how can I return a const string rather than define a const function?
The two are identical. Function attributes can go on either side of a function. e.g.
pure Bar foo() {...}
and
Bar foo() pure {...}
are identical. The same goes for pure, nothrow, const, etc. This is probably fine for most attributes, but it becomes quite annoying when const, immutable, or inout is involved, because they can all affect the return type. In order for those attributes to affect the return type, parens must be used. e.g.
const(Bar) foo() {...}
returns a const Bar, whereas
Bar foo const {...}
and
const Bar foo() {...}
return a mutable Bar, but the member function itself is const. In most cases what you want is probably either
Bar foo() {...}
or
const(Bar) foo() const {...}
since it's frequently the case that having a const member function forces you to return const (particularly if you're returning a member variable), but you can have any combination of const between the member function and its return type just so long as it works with what the function is doing (e.g. returning a mutable reference to a member variable doesn't work from a const function).
Now personally, I wish that putting const on the left-hand side were illegal, particularly when the excuse that all function attributes can go on either side of the function isn't really true anyway (e.g. static, public, and private don't seem to be able to go on the right-hand side), but unfortunately, that's the way it is at this point, and I doubt that it's going to change, because no one has been able to convince Walter Bright that it's a bad idea to let const go on the left.
However, it is generally considered bad practice to put const, immutable, or inout on the left-hand side of the function unless they're using parens and thus affect the return type, precisely because if they're on the left without parens, you immediately have to question whether the programmer who did it meant to modify the function or the return type. So, allowing it on the left is pretty pointless (aside perhaps for generic code, but it's still not worth allowing it IMHO).