5

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.

Daksh Gargas
  • 3,498
  • 2
  • 23
  • 37
  • Possible duplicate of [what is the difference in between ''const'' and ''final'' keyword in Dart?](https://stackoverflow.com/q/50431055/608639) – jww Dec 27 '18 at 15:37

2 Answers2

5

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.

lrn
  • 64,680
  • 7
  • 105
  • 121
  • "As an opposing opinion" My intention was not to argue that it should not be static, just that changing it to `const` would be a breaking change. Lots of great information in your answer though, as always. – Günter Zöchbauer Jul 16 '18 at 08:02
  • 1
    Good point, I'll change it to not be opposed :) – lrn Jul 16 '18 at 08:07
  • I guess I still didn't understand the reason behind that statement. And as 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 realise that they have done the exact same thing here. – Daksh Gargas Jul 16 '18 at 09:04
  • https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/painting/text_style.dart – Daksh Gargas Jul 16 '18 at 09:07
  • "that statement" Not sure what you mean by that. You can have different const instances of a class with a const constructor, this is why the values are held by instance fields instead of static fields. Static fields can only have a single value per class. Canonicalization means that there won't be more than one const instance with the same constructor parameter values. – Günter Zöchbauer Jul 16 '18 at 09:33
  • I guess I'm just too dumb to understand all this right now. I'm am unable to connect any of those explanations with my question, it's not that I am not getting what you are saying. – Daksh Gargas Jul 16 '18 at 09:58
  • I found it confusing as well when I started working with Dart and to some degree still do, so I think this is no reason to worry. "purpose of assigning `const` value to a `final` variable in dart?" As lrn said it's probably not the best design if there is no specific reason to have it an instance field. My argument was that just replacing `final` with `const` won't work because `const` alone is invalid at this place - it would need to be `static const` and that might need to change code that uses the class. – Günter Zöchbauer Jul 16 '18 at 10:12
  • So with an isolated view at the `RandomWordsState` class it's not entirely clear, but because the field is private it should be easy to make the necessary changes to make the code work with `static const _biggerFont = const TextStyle(fontSize: 18.0);` – Günter Zöchbauer Jul 16 '18 at 10:12
0

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

enter image description here

I haven't found where this suggestion comes from, but it makes sense because local variables can be const without static

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567