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.
Related
I'm trying to do something that would be a basic feature in any other Object Oriented Language but for some reasons in Dart, I can't manage to do it. I'm new to Dart so this question might be dumb, but I couldn't find any answer online.
I have a property that need to be calculated once and on the constructor. This is my code so far :
class Game {
String _wordChosen;
Game() {
final _random = Random();
_wordChosen = WORDS[_random.nextInt(WORDS.length)];
}
}
WORDS is a list defined outside the class. My error is on the Game constructor :
not_initialized_non_nullable_instance_field.
I don't want to set the _wordChosen variable to a default value as that would make no sense (it would be overwritten right when the constructor is run).
I also don't want to set the property as nullable as again, it would make no sense.
i think the answer is using the keyword late to make compiler know that you will initialize the variable before using it but not now like below
late String _wordChosen;
i think this is your solution and it in null safety documents here
i hope this answer helps you
class Foo {
final DateTime date;
static final DateTime defDate = DateTime.now();
Foo([this.date = defDate]); // Error
}
What's wrong in this code, I am providing a static final value as the default value to the optional parameter, but it isn't acceptable by Dart, can anyone please explain this behavior?
Edit:
// Global field
final DateTime defDate = DateTime.now();
class A {
void a([DateTime i = defDate]) => a; // Shouldn't have an error
}
class B extends A {
#override
void a([DateTime i = defDate]) => a; // Shouldn't have an error
}
Dart default values must be compile-time constant for a number of reasons.
First of all, the default value is considered part of the signature of instance methods.
Subclasses must override a method with parameters taking the same default value. That is meaningless if the value isn't known at compile-time.
More importantly is that there is not a single obvious time when the expression should be evaluated. Dart deliberately avoids evaluating anything before starting main to reduce startup latency. The only exception is compile-time constants because they can be evaluated entirely at compile-time.
That means that when you all a function with a default value the first time, the default value would not have been evaluated yet. It would definitely need to be evaluated at that point, at least if you omit an argument for the parameter, so the compiler might have to evaluate an arbitrary expression in the middle of a function call. Apart from the extra overhead, which is a problem by itself, the real issue is that it makes the code unpredictable.
In your example, the default value would be the DateTime.now() that happened to be the time when the function was first called.
The alternative would be evaluating the default value expression every time the function is called without an argument for that parameter. The Dart language team are considering that option (as a potential future move, no real current plans), but it would mean dropping the idea that the default value is a part of the signature.
Until the language does such a thing, the default value must be constant.
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.
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.
I know that, in Delphi, instance variables and global variables are initialized to zero (this has been asked here before).
However, what about static variables (class var)? I would expect class vars to be initialized to zero, just like global variables. But I've seen too many new Delphi compiler features that were still half-baked to assume that it works, without documentation that actually states a guarantee.
The Help has no index entry for "class var". The "Fields" topic mentions class fields, but does not specify whether they're initialized at program startup. And the obvious fix, of explicitly initializing them (class var X: Integer = 0;), doesn't compile ("';' expected but '=' found").
Are class variables initialized to zero? Is there documentation that explicitly states this?
I'm not aware of any documentation that explicitly states it, but class vars are just a special type of global variable, and globals get zeroed.