Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is it nesessary to use final for variables in flutter (dart)

Tags:

flutter

dart

I am confused as to when its compulsory to use final for variables.

According to documents and answers on StackOverflow,

If you make a StatefulWidget subclass with non-final fields, it will result in DartAnalysis warning

But I made this class and everything runs fine

class Order extends StatefulWidget {
  int hello = 1;

  @override
  _OrderState createState() => _OrderState();
}

class _OrderState extends State<Order> {
  pizza _pizzaOrder = new pizza();

  void setSize(String value) {
    setState(() {
      _pizzaOrder.size = value;
      print(++widget.hello);
    });
  }

I made a simple app and never used final or const anywhere in the program. So is it compulsory anywhere that I must use "final"/"const"? Or is just for optimization? And when should I use "final"?

like image 639
San Avatar asked Mar 05 '23 16:03

San


2 Answers

I think this is more related to the OOP principle SOLID, specifically open/close principle.

When you build a widget some cases you need some parameters to your constructor in order to define the attributes of your class. If you don't use final to your attribute, then it can be modified by other classes including the state.

In your case:

print(++widget.hello);

It works but it can cause unexpected behavior, imagine many classes accessing that attribute and modifying it, don't you want that right?

I found another reason StatefulWidget

StatefulWidget instances themselves are immutable and store their mutable state either in separate State objects that are created by the createState method, or in objects to which that State subscribes, for example Stream or ChangeNotifier objects, to which references are stored in final fields on the StatefulWidget itself.

like image 129
diegoveloper Avatar answered Apr 01 '23 23:04

diegoveloper


Adding to what diegoveloper have already said, imagine that you added a new parameter to the Order StatefulWidget and you're running the app so want it to hot reload.

The order widget will be recreated, but as it was a hot reload the State object will remain there with its existing values. In that case, you should be persisting this state in the State object, but in your example, the value in hello will be lost (i.e. will reset back to 1).

This way you won't lose hello state:

class Order extends StatefulWidget {
  Order({this.hello});
  final int hello;

  @override
  _OrderState createState() => _OrderState();
}

class _OrderState extends State<Order> {
  pizza _pizzaOrder = new pizza();
  int _hello;

  @override
  initState() {
    _hello = widget.hello;
  }

  void setSize(String value) {
    setState(() {
      _pizzaOrder.size = value;
      print(++_hello);
    });
  }

However, let's say in a parent widget you are creating it like this:

Order(hello: 1);

If you change the parent to:

Order(hello: 2);

And then again you hot reload, the parameter is final, and the StatefulWidget gets recreated, the State object is maintained, but then it doesn't update it's value according to the widget's new parameter. For that, you would use didUpdateWidget then:

class Order extends StatefulWidget {
  Order({this.hello});
  final int hello;

  @override
  _OrderState createState() => _OrderState();
}

class _OrderState extends State<Order> {
  pizza _pizzaOrder = new pizza();
  int _hello;

  @override
  initState() {
    _hello = widget.hello;
  }

  @override
  void didUpdateWidget(Order oldWidget) {
    super.didUpdateWidget(oldWidget);
    setState(() {
      _hello = widget.hello;
    });
  }

  void setSize(String value) {
    setState(() {
      _pizzaOrder.size = value;
      print(++_hello);
    });
  }

I deviated a bit from the question, but I thought it was somehow relevant. :)

like image 20
Feu Avatar answered Apr 01 '23 22:04

Feu