What is the purpose of assigning `const` value to a `final` variable in dart? [duplicate] - dart

This question already has answers here:
What is the difference between the "const" and "final" keywords in Dart?
(16 answers)
Closed 4 years ago.
So I was doing the first example for Flutter, and under
Step 4: Create an infinite scrolling ListView,
I encountered this piece of code:
class RandomWordsState extends State<RandomWords> {
final _suggestions = <WordPair>[];
final _biggerFont = const TextStyle(fontSize: 18.0);
...
}
But I found the following line a little spooky.
final _biggerFont = const TextStyle(fontSize: 18.0);
My question is, what is the purpose of assigning a constant value to a final variable?
I know that
Compile-time constants are canonicalized,i.e. no matter how many times
you write const MyObj(0, 0),you only create one object.
This may sound useful, but you can simply create the const variable to hold the value and use that variable instead.
Well, don't you think it's kinda redundant? I get it that the developers at Flutter wanted to create a compile-time constant object, but hey! you are assigning that value to a final variable. Which is somewhat the same thing.
Any thoughts?
UPDATE
I googled some definitions, I found that
const constructors cannot have a body and It's class must not have
any non-final fields
So is this the reason why we used the const keyword? Because if you'll look at the TextStyle class's design, you'll realize that they have done the exact same thing here.

I personally think
final _biggerFont = const TextStyle(fontSize: 18.0);
looks like a mistake, and that that alone is reason enough to change it.
The member is only used inside the same class, so there is no reason not to make it static. Then it will not take up one extra memory location for each instance of the class, all pointing to the same value. (That's assuming the compiler doesn't recognize the field as always having the same value, and just inlines the value everywhere).
If the member is static, it might as well also be const, so I'd write it as:
static const _biggerFont = TextStyle(fontSize: 18.0);
This assumes that the code is what I found by searching for final _biggerFont = const.
If there is a subclass in the same library which overrides _biggerFont, then it does need to be an instance variable. It could still be a getter instead of a field, then. Whether that's an efficiency improvement depends on how the class is used, and how well a compiler optimizes a final field that always has the same value.
In any case, creating a private instance member which always has the same constant value looks like something that should just be a static constant to begin with, and code that looks like a mistake is confusing to read. I'd rewrite it (or document it) just for that reason - to avoid the reader being confused about why it is the way it is.

const values are canonicalized.
This means no matter how often your code contains
final _biggerFont = const TextStyle(fontSize: 18.0);
there will only a single const TextStyle(fontSize: 18.0) instance.
Using const for class' fields requires static, this would not allow to access its value using a reference to an instance of RandomWordsState.
There are different preferences for classes with const constructors
http://dart-lang.github.io/linter/lints/avoid_field_initializers_in_const_classes.html
AVOID field initializers in const classes.
Instead of final x = const expr;, you should write get x => const
expr; and not allocate a useless field. As of April 2018 this is true
for the VM, but not for code that will be compiled to JS.
and top-level fields
http://dart-lang.github.io/linter/lints/prefer_const_declarations.html
PREFER using const for const declarations.
Const declarations are more hot-reload friendly and allow to use const
constructors if an instantiation references this declaration.
The IDE also suggests to replace final with const for local variables that are initialized with constant values
I haven't found where this suggestion comes from, but it makes sense because local variables can be const without static

Related

Can late and final be used together?

I am trying NNBD as of now and I would like to know if you can use the new keyword late and final together.
From what I understood, a late property can be set anywhere. You are basically telling the analyzer that it will not be null when used.
I think that is kinda dangerous in some situations.
So I am wondering if you can add a late final in NNBD, this would tell the analyzer that the property must be initialized within the class constructor.
There is a question similar but I guess there wasn't null safety at the time:
Dart. Late initialize final variables
You can declare a late final variable.
If you declare it with an initializer, late final foo = computeSomething();, then it is a lazy final variable. You can't assign to the variable, but its value is only computed the first time the variable is read. (In my experience, this is never the right choice for local variables, even though the language allows it. If you care about lazy initialization of a local variable, you also almost always want to know whether it was initialized, and a lazy variable doesn't give you that information. It's also confusing that the code is executed out-of-order, and it doesn't allow you to use await in the initializer expression).
If you declare a late final variable without an initializer, you are allowed to write to the variable once. Because the variable is late, the compiler won't complain about assignments at compile-time, unless it's absolutely certain that you have assigned the variable already, and only if it's a local variable (because that's the only variables that the compiler attempts to track assignments to).
If the late final variable without an initializer is an instance member of a class, that means that the class interface has a setter. You need to be very, very careful about exposing late final variables in the public API of a class. (Read: Don't do that!)
It's better to use late variables internally and guard access to the fields, so you can ensure that nobody assigns the variable twice. The goal of a late final variable is not to throw if it's assigned twice. It should never be assigned twice. It's there to allow allow code which knows for some reason that the compiler cannot comprehend, that the variable is only assigning once. So, only allow access to late final variables to code which are aware of that reason, and which maintains the invariant.
Yes!
You can see this pattern commonly used when initializing AnimationController.
class _MyState extends State<MyPage> with SingleTickerProviderStateMixin {
late final AnimationController _controller;
#override
void initState() {
super.initState();
_controller = AnimationController(vsync: this);
}
}
And you can use it for lazy initialization, like:
class Foo {
late final int i = calculate; // Initialized only when used.
int get calculate => ...;
}
Short answer: No, you'll not get any help from the analyzer.
From the nnbd language spec:
It is an error if a top level variable or static variable with a
non-nullable type has no initializer expression unless the variable is
marked with a late or external modifier.
It is an error if a class declaration declares an instance variable
with a potentially non-nullable type and no initializer expression,
and the class has a generative constructor where the variable is not
initialized via an initializing formal or an initializer list entry,
unless the variable is marked with a late, abstract, or external
modifier.
late final int foo; basically turns off null awareness for foo. It seems to be the equivalent of using implicitly unwrapped optionals in Swift, which can be hazardous, if you familiar with that.
https://github.com/dart-lang/language/blob/master/accepted/future-releases/nnbd/feature-specification.md
Besides that, the static analyzer does not warn you about trying to reset a late final.
Let D be a late and final local variable declaration named v. It is a run-time error, throwing an instance of LateInitializationError, to assign a value to v if a value has previously been assigned to v.
https://github.com/dart-lang/language/blob/master/accepted/future-releases/nnbd/feature-specification.md#late-fields-and-variables
Using late means you need to know exactly when things are being initialized and used.

Dart: Why can't constant variables be an instance variable? [duplicate]

This question already has an answer here:
Why only static fields can be declared as 'const'?
(1 answer)
Closed 11 months ago.
https://www.dartlang.org/guides/language/language-tour#final-and-const
In Language Tour of Dart docs, it says "Note: Instance variables can be final but not const. Final instance variables must be initialized before the constructor body starts — at the variable declaration, by a constructor parameter, or in the constructor’s initializer list."
But it's possible to make a constant object using a constant constructor. Why is it not possible to declare a constant variable as a member variable in Dart?
const means compile-time constant.
If you need to create an instance at runtime to create the value, it's not a compile-time constant anymore and therefore its members also can't be const.
Static members do not need an instance to be created and can therefore be constant no matter if the class has a const constructor or if it is used with const or not.
Why is it not possible to declare a constant variable as a member
variable in Dart?
Lets first define what member or instance variables are. Instance variables are basically things that define properties of an object. So, an object of a Car class made like Car(name: "Mercedeces", price: 500000) will have different member property values than Car(name: "Toyota", price: 10000).
Now having an instance variable as final basically means that once you define a Car object with name Mercedes you absolutely can not change the name of the object at run time. You suppose need a Car with name BMW so make a new object. This makes sense when allowing instance properties as final.
Now, lets look at const. const are compile time constants. Suppose you are allowed to define the name instance variable of Car as const. Doing this basically means, no matter how many instances you create of the Car object, all of the names will be the same and just like final members you cannot change it. The first part sounds odd. Not all cars will have the same name, that is contradictory to what instance or object of a class means. A object property may be immutable, using final but definitely will not have the same values. You would want to be able to makes instances of Mercedes sometimes and BMW sometimes. So, it makes no sense to make a instance property as const. This is why dart doesn't allow const without a static keyword. You need a static keyword beside a const property inside a class because only then it conforms to the definition of instance properties.
You can have constants inside a class but they will not be classified as instance variables. The key relies on the difference between final and const, you can't have const instance variables because constants are not variables.
final variables can only be assigned once but this happens at runtime.
the const keyword indicates a compile time constant.
Constants inside classes must be static though, so you could write something like:
class MyClass {
static const kMyConstant = 100;
void talk() {
print('My constant is $kMyConstant');
}
}
This is perfectly valid in dart.
Simply because if you want something const, it has to be done in compile-time, so either:
The entire instance is const: This is done by const-constructor.
The entire instance is not const.
You mark only one field const is meaningless.
E.g. const means "only one" there: you can use Car class to create a lot of Car-instances, then you say your wheel is const, so you share a wheel among all Car?
But you can make Car teslaCar = Car.fromModel(type: "Tesla") get the only one compile-time model const Car.

Do you need to use the "new" keyword in Dart?

In my Dart based application I just noticed that I can omit the new keyword and everything works perfectly fine.
Instead of final widget = new Widget(); I can also use final widget = Widget();.
Does this have any effect in code?
No, it does not. With Dart 2 (click for the announcement with more information) the new and also const keywords were made optional.
This means that new Widget() does the exact same as Widget() on its own.
The const keyword can, however, change a value that would not be a const implicitly to a const.
So you will have to explicitly specify const when needed.
In Dart 2, if you invoke a constructor like a function, without a new or const in front, then it is equivalent to using new.
If you want a const invocation, then you should put const in front.
Inside a const expression, you don't need to write const again, and in some contexts that require const expressions (like switch case expressions and initializers of const variables), you don't even need the outer const.
So you don't ever need to write new.
Dart language team wants to allow expressions where you can insert either new or const and still have the invocation be correct (that is, a const constructor with constant arguments) to default to inserting const instead of new, hopefully in an early update to Dart 2.
For that reason, I recommend writing new it in front of Object(), or any other const constructor where you need the object to be a new instance. That's a very rare case, usually you don't care about the identity of your immutable object (which is why inserting const is considered a good idea). (That plan didn't pan out, so you can ignore this.)
The new keyword was made optional in Dart 2. As of now, calling a class will always return a new instance of that class. As per my recommendation, you can use it (NOT MANDATORY) outside of a Layout definition, but omit in inside Layouts.
One more point which I would like to share with you guys is that if you use new or const keyword while declaring widgets, you are also able to see the + icon which you can use to collapse and expand the widget body code. This is useful when you want to collapse/hide the rest widget code in dart file while working on another widget code in the same file.

Using "final" for a Class instantiation

I came across the following code the other day (below) and wondered if it achieves anything of significance in Dart other than the fact that the Class instantiation cannot be changed. I did read some SO posts regarding Java, however they didn't appear conclusive, and don't necessarily apply to Dart. I would not have coded it that way (with final), however perhaps I should. Is there any major significance to using "final" in this instance and what does it achieve?
import 'dart:math';
final _random = new Random();
From Dart: Up and Running:
If you never intend to change a variable, use final or const, either instead of var or in addition to a type. A final variable can be set only once; a const variable is a compile-time constant.
A local, top-level, or class variable that’s declared as final is initialized the first time it’s used.
So there are three benefits to using final here:
If some code erroneously tries to set _random another time, an error will be generated.
It is also clearer to other programmers (or the same programmer at a later date) that _random is never intended to be changed.
_random is not initialized until it used, so the application will start faster.
For those reasons, I would consider this a good use of final; certainly the code would "work" without it, but it's better this way.
In short, I think the book offers sound advice: "If you never intend to change a variable, use final or const".
From the documentation :
A local, top-level, or class variable that’s declared as final is initialized the first time it’s used. Lazy initialization of final variables helps apps start up faster.

What is the syntax for implicit cast operator in dart?

I would like to cast instances of my custom class A to int. What is the syntax of the implicit cast operator? (I thought I remembered that there is such a feature but I can't find it on the web)
int a = (new A());
You can also use as to help tell the tools "no, really, treat this object as this type".
A good example of this is when you have to deal with dart:html's querySelector() function.
FormElement form = querySelector('#sign-up') as FormElement;
In the above, the object returned by querySelector('#sign-up') is checked that it is really an instance of FormElement.
Learn more at https://www.dartlang.org/docs/dart-up-and-running/ch02.html#operators
Type annotations are not allowed to affect behavior in Dart. If you're not running in checked mode, then this:
int a = new A();
will work the same as this:
var a = new A();
at run-time. In other words, when not in checked mode, you're welcome to store your A in a variable annotated as an int, but no actual conversion takes place.
If you are running in checked mode, the first form will give you a runtime exception.
I'm not sure, but I think what you're asking for is a way to define a conversion between your class A and int that will happen automatically when "cast" to an int. No such thing exists, to my knowledge. You should simply define a method to do so. For example:
int a = new A().to_i();

Resources