Flutter: Late Initializing a "widget-dot" Class-level Variable in a Stateful Widget -- What's Going on?

130

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.

Share:
130
Nerdy Bunz
Author by

Nerdy Bunz

Hi. Coding and creating new things gets me excited like a fizzy drink, but sometimes I run into headaches, so I come here for help. But I make sure to help other people too, so I think it works out. Apparently my posts often contain language considered extraneous by the pool cleaning robots who dutifully scrub it away on their regular patrols. "Bzzzz! Bzzzz!!! Desaturate, desaturate!" Fortunately, it's ACCESS DENIED for any editing attempts on this lil' article. They'll have to re-route the encryptions... and good luck with that. Oooo! Butterfly!!!! Anyway... when I'm not on here, I like to spend time sniffing and paddling my way around the enchanted river-forest near my house... and knitting my very own apps.

Updated on January 04, 2023

Comments

  • Nerdy Bunz
    Nerdy Bunz over 1 year

    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?

    • Christopher Moore
      Christopher Moore about 2 years
      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.