3

Consider the following class level property inside the state class of a stateful widget:

int myInt = widget.int;

Android Studio informs that: "The instance member 'widget' can't be accessed in an initializer."

(I understand what this error means).

So then if we add the late keyword, it appears to be fine:

late int myInt = widget.int;

However... this is surprising to me that I’m allowed to do all that in one line — I thought that late variables had to be not set/set as null:

late int myInt;

... and then assign inside onInit.

Since I didnt declare when to assign it, I dont know when the assignment takes place.

The question is:

Is the one-liner “late int myInt = widget.int;” exactly equivalent to assigning it myself in the initState method?

Nerdy Bunz
  • 6,040
  • 10
  • 41
  • 100
  • 1
    It's not exactly equivalent, though basically the same in effect. Using the one-line `late` solution assigns the initial value to the variable the *first* time it's accessed somewhere later on. Doing it in initState of course just initializes it there, regardless of whether the variable is marked late or not. – Christopher Moore Mar 24 '22 at 00:37

3 Answers3

6

The late keyword in Dart has 2 distinct usages, melt into a single keyword.


The first usage, e.g. late int i:

This usage is well-known: delay assigning a value until later. This is most commonly used to make a field non-nullable, even though you might not have the value right away. I'm sure you are familiar with this usage.

The second usage, e.g. late int i = 0:

This is to delay the value calculation until the field is being accessed. This is useful when the value is expensive to calculate, so you might want to delay its calculation until it's needed for the first time. It's stated on the official documentation:

When you do this, the initializer becomes lazy. Instead of running it as soon as the instance is constructed, it is deferred and run lazily the first time the field is accessed. In other words, it works exactly like an initializer on a top-level variable or static field. This can be handy when the initialization expression is costly and may not be needed.

So basically, depends on whether you assign a value right away (on the same line), Dart will decide which of the 2 usages you are using. If you write late int i it will be the first usage, if you write late int i = 0 or late int i = calculateValue() it will be the second usage: delay the calculation until when the field i is accessed for the first time. It's like lateinit in Kotlin or lazy in Swift.

Now back to your case. By assigning a value on the same line as the late keyword, you are using the second usage, basically "lazy init" until the field is accessed for the first time. By the time it's accessed, this class would've been instantiated, so (by that time) you are allowed to use the this keyword.

WSBT
  • 33,033
  • 18
  • 128
  • 133
0

In the first case Android studio throws that error because int myInt requires a value the moment you are declaring it.

In that particular moment, in the Statefull widget state, the widget object is not accessible.

In the second case:

late int myInt = widget.int;

That is a valid one line declaration and assignment of the variable, but the effect is a bit different from the onInit alternative.

The late keyword works in a lazy way. Instead of running as soon as the instance is built, it run the first time the field is used. In that moment the widget object will be accessible.

Take a look at the answer to this question, it can be helpful: here

Assigning the value inside the onInit guarantees that the value is actually assigned only once when the widget is initialized.

L. Gangemi
  • 3,110
  • 1
  • 22
  • 47
-1

widget.xxx corresponds to the value of xxx of the instance of a widget, ie the widget once it exists.

So when you use widget.xxx in initialisation of the widget, the var xxx does not exists.

That's why the dart compiler tell you The instance member 'widget' can't be accessed in an initializer .

By adding the keyword late in front of the declaration, you tell the compiler that this variable will be defined later.

But be careful, it will then really have to be defined later (in initState for example) and in any case before any use.

This error comes from the fact that dart is now a null safety aware language.

That is to say a language that strives to ensure that no variabales can have a null value. This is for reasons of code quality and greater code security.

Alaindeseine
  • 3,260
  • 1
  • 11
  • 21