This question already has answers here:
Difference between assigning the values in parameter list and initializer list
(2 answers)
Closed 1 year ago.
This code snippet
class SomeWidget extends StatelessWidget {
final String aString;
SomeWidget(this.aString);
compiles without error or warning. However, this code snippet
class SomeWidget extends StatelessWidget {
final String aString;
SomeWidget(String inputString) {
this.aString=inputString;
}
gives an error message that all final variables must be initialized and aString isn't, and how aString can't be used as a setter because it's final. Removing the final keyword eliminates the error messages.
I'm unclear what's going on here. I saw this and this SO item, but honestly I'm still struggling to understand. I think the problem, for me, stems from how I was taught my two code snippets are functionally identical.
When you declare a variable as final, this means that the state\value of this variable will not change during the life cycle of this widget.
Thus, when you declare:
final String aString;
You are telling the framework, that the value of aString, will not change, because it's final. However, when you use the setter, you are trying to do the exact opposite of what you just promised Flutter, and you are attempting to change what should be final = aka non-changeable.
Related
This question already has an answer here:
Is there a difference in how member variables are initialized in Dart?
(1 answer)
Closed 9 months ago.
It looks easy, but not working. I have model in Dart like this:
class FormTab {
String caption;
FormTab(dynamic m) { // where m will be Map
this.caption = m['caption'] ?? "No caption";
}
}
But still I have error message: Non-nullable instance field 'caption' must be initialized. Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'.
What is wrong? I set value caption, but still I have error. I tried caption
The body of a constructor in Dart is not part of the initializers. You need to put that into the initializer list:
class FormTab {
String caption;
FormTab(dynamic m) : caption = m['caption'] ?? "No caption";
}
Please note that if you know it's going to be a map, it might be better to make it a map. The earlier you switch from dynamic to actual types, the easier it is to catch errors.
https://dart.dev/guides/language/effective-dart/design#avoid-public-late-final-fields-without-initializers
AVOID public late final fields without initializers.
Unlike other final fields, a late final field without an initializer
does define a setter. If that field is public, then the setter is
public. This is rarely what you want. Fields are usually marked late
so that they can be initialized internally at some point in the
instance’s lifetime, often inside the constructor body.
Unless you do want users to call the setter, it’s better to pick one
of the following solutions:
Don’t use late. Use late, but initialize the late field at its
declaration. Use late, but make the late field private and define a
public getter for it.
The above explanation is abstract and I have no concrete image of what kind of risk this rule envisions.
I would be grateful if you could give me a hint as to how to think.
The risk is that you accidental try to assign a value twice, which will result in an error.
late final String a;
void someMethod() {
a = "a";
a = "b";
}
The above code compiles perfectly fine and is valid code because of the late but leads to a crash.
As for the suggested solutions
Don’t use late.
Use late, but initialize the late field at its declaration.
final String a = "b";
// or
late final String a = "b";
void someMethod() {
a = "a";
a = "b";
}
This makes it that the above code doesn't even compile, making it sure that the crash doesn't happen.
Late modifier means a variable's value is not known during declaration but will definitely get initialized and not null when it's accessed.
When we declare a variable as final, it means that it will only assigned once. Therefore, all the final fields has to be initialized either at declaration or inside the class constructor.
Given above facts, for one to declare a late final variable as public would probably a mistake. One should either pass the value to final field as class constructor parameter, or declare the late final field as private and initialize it internally.
Let see the example why late final field should not be made public
class Coffee {
late final String temperature; // public field as there's no prefix underscore, e.g. _temperature
// based on description from the guide, a setter will be created automatically for public late final
set temperature(String val) => temperature = val;
// again, do you think you would want above?
// as it's final field, it means it should only be initialized once!
// The creation of the setter for late final (public field) does not make too much sense
// Therefore usage late final as public field is rarely what you will want
}
Not sure if it's true, but I think this advice is to enforce better architecture. If field is final then you can set it value only once and almost always you need to initialize it from within the class it belongs to.
But if setter for final field is public then people might attempt to set it value from elsewhere AFTER it is already initialized, and this will lead to an error.
UPD: two sections above there is this advice, that basically summarizes my point:
Objects shouldn’t generally expose more state than they need to.
...and setter is not needed after final field has been initialized.
what does <RandomWords> mean? what is this grammar of Dart language?
class RandomWords extends StatefulWidget {
#override
State createState() {
return new RandomWordsState();
}
}
class RandomWordsState extends State<RandomWords>{
#override
Widget build(BuildContext context) {
return new Scaffold(
);
}
}
what does <RandomWords> mean? what is this grammar of Dart language?
You are specifying what State this state is about, in the same way that when you say something like:
List<String> a;
You are saying what this List is made of.
In another words, it means the State class is a Generic class.
In the documentation of List class you will see they actually refer to it as:
List<E> class.
So, whatever type you put in the List, all of the methods related that contains E (as a argument or as a return) will have the signature adjusted accordingly, i.e.:
last ↔ E
Returns the last element.
As you can see, the last method returns the same type that the List contains, which is the expected.
The use of this is mostly for type safety, so if you try to insert a number into a List< String>, the compiler will know and will detect the mistake.
Also, if you're the one developing a Generic class, it will help avoid code duplication, because you won't have to write a implementation for each possible List type in the world.
When defining your class, you can do something as follows (Example from dart Language Tour):
abstract class Cache<T> {
T getByKey(String key);
void setByKey(String key, T value);
}
And, in their words:
In this code, T is the stand-in type. It’s a placeholder that you can think of as a type that a developer will define later.
Also, as a last tip, we can see on the documentation of the State class linked above that the generic type needs to be something that inherits from Stateful Widget, so you don't try to create a State< Int>, for example.
State < T extends StatefulWidget > class
My question is pretty straightforward, i've a Dart class like so
import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
class Weather extends Equatable {
final String cityName;
final double tempCelsius;
final double tempFahrneit;
const Weather({
#required this.cityName,
#required this.tempCelsius,
this.tempFahrneit,
});
#override
List<Object> get props => [
cityName,
tempCelsius,
tempFahrneit,
];
#override
String toString() {
return [
cityName,
tempCelsius,
tempFahrneit,
].toString();
}
}
I'm using Equatable to ease the objects comparison, i also used the const keyword on the class constructor (not sure about this i've heard when used on a class constructor it makes Dart look first if it has the same class with same properties before instanciate it).
When i look up on DevTools, i always get multiple class instances when calling a function although it's always the same parameters, and the garbage collector keep it event though i pop up / destroy the view (Scaffold in Flutter context).
For now i'm just testing it with a small class, but this'll be a mess if it's one big of a class, even though i think in this case the garbage collector will surely dispose the unused classes, but i want to know if i can solve this "problem" with some sort of Dart/Flutter ways.
If you create your objects with const Weather(...) you should not see multiple instances anymore.
Watching the garbage collector is usually not a good idea, you can trust that it will destroy your objects when the GC algorithm gets to it.
Dart's garbage collector is optimized for creating many small objects and throwing them away together. So you probably do not have to worry about this at all.
Okay so I'm trying to learn Dart by following flutter tutorials.
In the example below, right after the object is declared, an instance of itself is "created" (or at least I think so) and I don't understand why.
class CounterDisplay extends StatelessWidget {
CounterDisplay({this.count}); // What does this line do ?
final int count;
#override
Widget build(BuildContext context) {
return Text('Count: $count');
}
}
This code is from the tutorial found on this page:
https://flutter.dev/docs/development/ui/widgets-intro#changing-widgets-in-response-to-input
The line in question is this one :
CounterDisplay({this.count});
Could someone explain to me what does this line do and why it's here?
This doesn't create an instance of the object.
It is instead what we call a "constructor". Such syntax allows specifying custom parameters that need to be passed when creating the object.
See the dart documentation on constructors for more informations.
This make argument optional when create new object, or pass the variable name when creating object .