How can I initialize a mixin's immutable data in Dart? - dart

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 is final, so I cannot set it in Meat's constructor.
I don't want to make Salt a class because Meat may need to extend from something else.
And I want to keep pinches immutable.
Any way to do it? Thanks in advance.

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);
}

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.

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;
}
}

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.

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;

Related

How to use extended generics in Dart? [duplicate]

I'm trying to call a static method from a generic type I receive.
Is that even possible?
Furthermore, I apply a Type constraint in order to only manipulate the object from its parent class.
Here is a short example of what I'm trying to achieve:
class A {
static func() {
print("A");
}
}
class B extends A {
static func() {
print("B");
}
}
concret<T extends A>() {
T.func(); // I expected a print('B')
}
main() {
concret<B>();
}
No, it's not possible.
Dart static method invocations are resolved at compile-time, so it's not possible to call them on type variables which only have a value at run-time.
If it was possible, it would be completely unsafe. Anyone can create a class C extending A which does not have a static func member and invoke concret<C>();. Since static members are not inherited, it would have to give you a run-time error, and there is nothing you can do to detect that at compile-time. That is the primary reason why it is not allowed.

Is there a way to access a mixin's private variable in the class using the mixin?

In dart when creating a mixin, you can declare properties and methods like a class. When declaring a private property/method, it seems the inheriting class should also have access to this private member (see below for example).
Is there a way to access a mixin's private variable in the class using the mixin?
If it's not possible, how can I declare a member in the mixin object but make it private in the inheriting class's interface.
mixin.dart
mixin A {
String propertyOne = '1';
// This property is not accessible to any inheriting class.
int _privateProperty = 2;
}
class.dart
class B with A {
String get mixinString => propertyOne;
// This property is not accessible to the B class.
int get mixinInt => _privateProperty;
}
No. A property being library private means that you can only express its name inside the same library. In any other library, the identifier _privateProperty is a different name, one private to that other library.
If you cannot declare both mixin and class in the same library, and you definitely need access to the property, then you can do any number of things to allow that.
Make the property public and tell people not to use it except in subclasses. They still can if they want to.
Make the property public and mark it #protected, to have the analyzer tell people to not use it except in subclasses. They still can if they want to.
Keep the property private and provide a separate method to access it:
mixin A {
// This property is not accessible to any inheriting class.
int _privateProperty = 2;
static int getPrivateProperty(A a) => a._privateProperty;
static void setPrivateProperty(A a, int value) {
a._privateProperty = value;
}
}
Anyone can still get to the property if they really want to, but they need to know that
it comes from A.

Is it possible to force a Type to be used only in static fields?

I'm working on a library, and I have a implementation pattern users are required to follow:
class MyView extends LibView {
static Foo f = Foo();
#override
void render(){
use(f); // f should be static, otherwise things not work correctly
}
}
I would like to tell the compiler that, if someone ever does this, it's incorrect:
class MyView {
Foo f = Foo(); // Error: Foo can only be used in Static field.
...
}
Anyone know if this is possible? I find it really hard to find good docs on these sorta of language details when it comes to dart.
[EDIT] Since the "why" question always comes up, imagine something like:
class ViewState{
Map<int, Object> props = {};
}
ViewState _state = ViewState();
class View {
View(this.state);
ViewState state;
static int _key1 = getRandomInt();
void render(){
print(state(_key1))
}
}
// These should both print the same value off of state since the 'random' int is cached
View(_state);
View(_state);
If the key's were not static, everything would compile fine, but they would not print the same results.
What you properly need are a singleton which can be created in different ways in Dart. One way is to use a factory constructor like this:
class Foo {
static final Foo _instance = Foo._();
factory Foo() => _instance;
// Private constructor only used internally
Foo._();
}
void main() {
final a = Foo();
final b = Foo();
print(identical(a, b)); // true
}
By doing it like this, there will only be one instance of Foo which are then shared each time an instance are asked for. The instance are also first created the first time it is asked for since static variables in Dart are lazy and only initialized when needed.
I just want to do the functional equivalent of
int someUniqueKey = 0, or MyViewEnums.someUniqueKey but do it with a typed object rather than a int/enym, like: Object<Foo> someUniqueKey = Object<Foo>(). In order for this to work with Objects, it needs to be static. It's similar to how int someUniqueKey = random.nextInt(9999) would have to be static in order to be used as a key that all instances could share. That way keys are auto-managed and unique, and people don't need to assign int's, strings, or whatever. It also has the advantage of letting me use the type later for compile time checks.
bool prop = getPropFromRef(_prop1Ref); //Will throw error prop1Ref is not Ref<bool>
I think I've figured out something that does the trick using darts package-level methods.
class Ref<T> {}
// Re-use existing ref if it already exists
Ref<T> getRef<T>(Ref<T> o) => o ?? Ref<T>();
class RefView {}
// In some other package/file:
class MyView extends RefView {
static Ref<bool> prop1Ref = getRef(prop1Ref);
static Ref<int> prop2Ref = getRef(prop2Ref);
}
This will make sure that prop1 and prop2 have the same values across all instances of MyView and it will throw an error if these are not static (since you can not pass an instance field before Constructor)
This still has the downside of a potential hard to spot error:
class MyView extends RefView {
static Ref<bool> prop1 = getRef(prop1);
static Ref<bool> prop2 = getRef(prop1); // passing prop1 to prop2's getRef, and they have the same<T>, compiler will miss it
}
But I think it might be preferable than having this potential error:
class MyView extends RefView {
//Both of these will fail silently, keys will change for each instance of MyView
Ref<bool> prop1 = getRef(prop1);
Ref<bool> prop2 = getRef(prop2);
}

How do getters and setters change properties in Dart?

I am struggling with the concept of getters and setters in Dart, and the more I read, the more I cannot grasp the underlying purpose. Take for example the following code:
main() {
Car car = new Car();
car.doors = 44;
print(car.doors); // 44
}
class Car {
int doors = 4;
}
Later, I decide to make “doors” a private variable, so I do the following:
main() {
Car car = new Car();
car.doors = 44;
print(car.doors); // 44
}
class Car {
int _doors = 4;
int get doors => _doors;
set doors(int numberOfDoors) => _doors = numberOfDoors;
}
According to the code, _doors is now a private variable, and so I cannot access it in main(). However, by manipulating doors, I can indirectly change the value of _doors, which is what I thought I wanted to prevent in the first place by making it a private variable. So what is the purpose of making a previously public variable into a private one, if you can still indirectly manipulate it? And, how are getters and setters even working to change the properties of these variables? I am trying to understand the fundamental concept, because without that, I don't understand how or why getters and setters are used.
Instance variables in Dart have implicit getters and setters. So for your example code, it will operate in exactly the same way, since all you have done is changed from an implicit getter and setter to an explicit getter and setter.
The value of explicit getters and setters is that you don't need to define both if you don't want. For instance we can change your example to only define a getter:
main() {
Car car = new Car();
print(car.doors); // 4
car.doors = 6; // Won't work since no doors setter is defined
}
class Car {
int _doors = 4;
int get doors => _doors;
}
Additionally, you can also add extra logic in a getter or setter that you don't get in an implicit getter or setter:
class Car {
int _doors = 4;
int get doors => _doors;
set doors(int numberOfDoors) {
if(numberOfDoors >= 2 && numberOfDoors <= 6) {
_doors = numberOfDoors;
}
}
}
The getter and setter functions allow us to make the class appear to have a property, without a explicit property being declared (_doors in your case). The property value may be calculated from other properties.
The getters and setters allow us to execute arbitrary code when the property is get or set.
Omitting a setter makes the property immutable.
An abstract class may declare getters and setters without bodies as part of a required class interface.

How to dynamically create a method or a setter in a class in Dart?

Is it possible to dynamically add an instance method or a setter to an existing class, either from within this class or from outside of it?
No, you can't add a real member to a class.
I said real member because you can simulate such feature with noSuchMethod(). Here a example :
#proxy
class A {
final dynamicMethods = <Symbol, Function>{};
noSuchMethod(Invocation i) {
if (i.isMethod && dynamicMethods.containsKey(i.memberName)) {
return Function.apply(dynamicMethods[i.memberName],
i.positionalArguments, i.namedArguments);
}
return super.noSuchMethod(i);
}
}
main() {
final a = new A();
a.dynamicMethods[#sayHello] = () => print('hello');
a.sayHello();
}
In the future this could perhaps be possible. See this excerpt from the article on Mirrors :
We’d like to support more powerful reflective features in the future. These would include mirror builders, designed to allow programs to extend and modify themselves, and a mirror-based debugging API as well.

Resources