How can I initialize a mixin's immutable data in Dart?
Solution 1
You can change the declaration of your mixin to:
mixin Salt {
int get pitches;
}
And then define the field inside the implementation class
class Meat with Salt {
final int pitches;
Meat(this.pitches);
}
Solution 2
By design it is not possible to declare a final member into a mixin because it is not possible to declare a constructor for initializing the final member, citing the docs:
However, in this proposal, a mixin may only be extracted from a class that has no declared constructors. This restriction avoids complications that arise due to the need to pass constructor parameters up the inheritance chain.
A compromise may be to declare a private member and implement only a getter.
_pinches
is visible only inside the library, it is read-only for library users.
mixin Salt {
int _pinches;
get pinches => _pinches;
}
class Meat with Salt {
Meat(int pinches) {
_pinches = pinches;
}
}
Note: the above pattern, because of the visibility rules, works only if the mixin and the mixed classes reside in the same library.
Solution 3
Similar to attdona's suggestion, but a little bit closer to what you really wanted, you could do it like
mixin Salt {
int _pinches;
int get pinches => _pinches;
void initSalt(int pinches) {
assert(_pinches == null);
_pinches = pinches;
}
}
class Meat with Salt {
Meat(int pinches) {
initSalt(pinches);
}
}
It's still not strictly final, but (so long as the mixin's in a different library so you can't change the private member directly) it's immutable at runtime. Not as good as if it could be properly final, but maybe close enough.
Solution 4
The following method allows you to set the data at a later time, and gets rid of the warning:
This class (or a class that this class inherits from) is marked as '@immutable', but one or more of its instance fields aren't final
mixin Salt {
final SaltData _saltData = SaltData();
int get pinches => _saltData.pinches;
set pinches(int extraData) {
_saltData.pinches = extraData;
}
}
class SaltData {
int pinches = 0;
}
So what I did is create a class SaltData
. This will store all the variables you need.
The private _saltData
variable is final, this will stop the warning.
Then use a getter and setter to retrieve and update the data.
int get pinches => _saltData.pinches;
set pinches(int extraData) {
_saltData.pinches = extraData;
}
If you want you can could expose the entire saltData object as well:
SaltData get saltData => _saltData;
Solution 5
I offer my take on a solution to this. By marking the variable late
you can make it final
. No warning will appear if you fail to initialize it so use with caution.
mixin Salt {
late final int pinches;
}
class Vegetable with Salt {
Vegetable(int pinches) {
this.pinches = pinches;
}
}
Nick Lee
Updated on December 08, 2022Comments
-
Nick Lee over 1 year
I am programming in Flutter using Dart 2.1.0, and come across this situation:
mixin Salt { final int pinches; // Immutable, and I want to delay initialization. // Cannot declare constructors for mixin } class Meat with Salt { Meat(int pinches) ... // How to initialize it? }
Salt
has no constructor, so I cannot use initializer list.pinches
isfinal
, so I cannot set it inMeat
's constructor.I don't want to make
Salt
a class becauseMeat
may need to extend from something else.And I want to keep
pinches
immutable.Any way to do it? Thanks in advance.