Should you use "extends" or "with" keyword for ChangeNotifier? - Flutter - flutter

I have seen several examples of a model extending ChangeNotifier using both 'extends' and 'with' keywords. I am not sure what the difference is.
class myModel extends ChangeNotifier {...}
class myModel with ChangeNotifier {...}
What is the difference between those two? Which one should I use?

You can use either extends (to inherit) or with (as a mixin). Both ways give you access to the notifyListeners() method in ChangeNotifier.
Inheritance
Extending ChangeNotifier means that ChangeNotifier is the super class.
class MyModel extends ChangeNotifier {
String someValue = 'Hello';
void doSomething(String value) {
someValue = value;
notifyListeners();
}
}
If your model class is already extending another class, then you can't extend ChangeNotifier because Dart does not allow multiple inheritance. In this case you must use a mixin.
Mixin
A mixin allows you to use the concrete methods of the mixin class (ie, notifyListeners()).
class MyModel with ChangeNotifier {
String someValue = 'Hello';
void doSomething(String value) {
someValue = value;
notifyListeners();
}
}
So even if your model already extends from another class, you can still "mix in" ChangeNotifier.
class MyModel extends SomeOtherClass with ChangeNotifier {
String someValue = 'Hello';
void doSomething(String value) {
someValue = value;
notifyListeners();
}
}
Here are some good reads about mixins:
Dart: What are mixins?
Dart for Flutter : Mixins in Dart

extends is used to inherit a class
with is used to use class as a mixin
Refer here to understand difference between mixin and inheritence: https://stackoverflow.com/a/860312/10471480
Refering to ChangeNotifier, the docs says
A class that can be extended or mixed in that provides a change notification API using VoidCallback for notifications.
Hence you can inherit it as well as use it as a mixin

I think this has to do with legacy support. The mixin keyword was introduced in Dart 2.1.0. According to the documentation, you should AVOID mixing in a type that isn’t intended to be a mixin:
For compatibility reasons, Dart still allows you to mix in classes
that aren’t defined using mixin. But, that’s risky. If the author of
the class doesn’t intend the class to be used as a mixin, they might
change the class in a way that breaks the mixin restrictions. For
example, if they add a constructor, your class will break.
If the class doesn’t have a doc comment or an obvious name like
IterableMixin, assume you cannot mix in the class if it isn’t declared
using mixin.
As Dart does not allow multiple inheritances the ChangeNotifier API allows it to be mixed in. As the documentation states:
A class that can be extended or mixed in that provides a change
notification API using VoidCallback for notifications.
IMHO to be aligned to the language specification Flutter should change the ChangeNotifier, separating those reusable implementations into Mixin Classes. At least the Dart documentation makes me think this is something that could not be supported anymore in a future release [the mix in of a non mixin class].
There are lot of discussions around this:
Make ChangeNotifier a mixin
Allow mixins in "extends" clauses

in Provider, Both allow to use notifyListeners(),But
Extend means that (ChangeNotifier) is superclass,
Mixin allows using the methods from (ChangeNotifier) class
also
You can extend one class
But can mixin more than one class
This is a good short article about difference:
Should use Extends or Mixin | Flutter Tips

Related

The member 'notifyListeners' can only be used within 'package:flutter/src/foundation/change_notifier.dart' or a test

I am using ChangeNotifier and i change their value and notify like below,
// Declare
ValueNotifier<bool> isDisplay = new ValueNotifier(false);
// Change value
isDisplay.value = false;
isDisplay.notifyListeners();
It's working fine. but it's raise warning like below,
Can we resolve this using proper implementation or other things ?
I was getting these errors too, more specifically, those 2:
The member 'notifyListeners' can only be used within instance members of subclasses of 'package:flutter/src/foundation/change_notifier.dart'.dart(invalid_use_of_protected_member)
The member 'notifyListeners' can only be used within 'package:flutter/src/foundation/change_notifier.dart' or a test.dart(invalid_use_of_visible_for_testing_member)
After a bit of research, I've come to some conclusions and a solution. Thought I should share it with people who encounter this problem.
The problem
What it says actually is quite obvious, “If you wanna call notifyListeners(), you have to do it in a subclass of ChangeNotifier or in a test file”
“But why is that?” Understandably, this was my second question. But before that, a little bit about where the heck that notifyListeners method is coming from
notifyListeners method
If you look at the implementation of ValueNotifier, it extends ChangeNotifier class:
and ChangeNotifier has a notifyListeners() method (which is why, in the first place, we can use this method) but not in a usual way:
It's protected.
#protected annotation in Dart | doc
[#protected annotation] Indicates that the annotated instance member (method, getter, setter, operator, or field) m in a class or mixin C should only be referenced in specific locations.
A reference from within the library in which C is declared is valid. Additionally, a reference from within an instance member in C, or a class that extends, implements, or mixes in C (either directly or indirectly), or a mixin that uses C as a superclass constraint is valid. Additionally, a reference from within an instance member in an extension that applies to C is valid.”
In a more worldly explanation: it can be used in subclasses that directly extends (or mixins) the ChangeNotifier class or in test files. Since you want to use it in your logic code, you have to do the first section in this paragraph: “extend or mixin ChangeNotifier where you want to call notifyListeners method.”
Where to extend (or mixin) the ChangeNotifier class?
You may be tempted to use it in your Stateful or Stateless Widget, and, since Dart is single-inheritance, you'd have to “mixin” the ChangeNotifier class to your class, but you'd be wrong.
1. Why you must not mixin to StatefulWidget
ChangeNotifier class defines its own dispose method. And since the class or mixin that mixins to your class supersedes the previous inherited methods, by looking at the methods of ChangeNotifier, you'll notice the dispose method (which is used to remove the listeners). So, if you mix ChangeNotifier to StatefulWidget, now your dispose would be ChangeNotifier's dispose rather than the State's dispose.
Remember, you have to release the resources used by State class no matter what. Normally, if you do not override the dispose method in your State, the framework does this for you and releases the resources by itself, which is cool; but since you just changed the dispose method's ancestor, framework will not trigger the required dispose method. And that will raise a runtime error.
2. Why you must not mixin to StatelessWidget
And on the StatelessWidget's case, now your widget would have an instance variable _listener that's not final which comes from the mixed ChangeNotifier. So, you couldn't define a const constructor, which is the most important part of a StatelessWidget (talking about widget rebuild and performance-related situations).
What to do?
In the end, a solution to this would be, to create a new class to manipulate value changes and extend or mixin ChangeNotifier to this class. Then you can call notifyListeners() method wherever and whenever you like! (but of course, don't call notifyListeners unless you use complex objects or send the same value)
Also, these classes are preferably called as 'Controller', 'ViewModel', 'BLoC', or any other name to state that they're mutating/controlling your values and trigger UI to rebuild when needed. (Which what you should do in the first place: separate your UI from your Logic layer).
Further readings
State management for minimalists
You do not need to call notifyListeners, as this is automatically called when a new value is set.
ChangeNotifier implementations like ValueListener should never require notifyListeners to be called manually.

Why stateful/stateless widgets extends and doesn't implements?

I have this question for a job interview, and i want to know why the stateful and staless widgets, use extends and why not use implements in Flutter/Dart?
Extends
extends is usually the go-to when you want to make a more specific version of a class.
When you extend a class, you inherit all properties, methods, etc.
If you want to override a method, you prefix the method with #override.
Implements
implements is when you want to make a whole new version of a class but you want to inherit the class type.
When you create a new implementation of a class, you are responsible for supplying everything necessary to make that class function.

Why should we use the 'override' key word in Kotlin for abstact class members?

If the base class has an abstract method or property, than these members must be overriden in the child class. The documentation says that i must use key word 'override' every time for such members, because i must implement methods or initialize properties in the child class. For example:
abstract class Dwelling {
abstract val buildingMaterial: String
abstract fun hasRoom() : Boolean
}
class RoundHut : Dwelling() {
override val buildingMaterial = "Stone"
override fun hasRoom() : Boolean {
return true
}
}
If an abstract method and a property must be overriden and implemented in child class any way (and compiler know this), than why we should write 'override' key word every time?
When you find yourself reading and understanding the implementing class, you have the explicit information that you're currently investigating an overridden one as it's explicitly marked as such. Kotlin likes to make things explicit and the documentation states
[...] we stick to making things explicit in Kotlin. So, Kotlin requires explicit modifiers for overridable members (we call them open) and for overrides
Java has an #Override annotation that is optional and not used by everyone although it has been considered a best practice (even as per Effective Java). Kotlin goes one step further by making it a compiler-enforced requirement.

Is there a way to combine multiple meta annotations into one?

At the moment we have a lot of classes in our codebase, who are using the same meta annotations. An example would be:
#autoEquatable
#immutable
#jsonSerializable
class SignInWithFacebookEvent extends LoginEvent {}
Is there a way in Dart where I can combine those into one? For example:
#event
class SignInWithFacebookEvent extends LoginEvent {}
This would be much simpler, and also if I would need to add/edit/remove another meta annotation from all event classes, I could just add/edit/remove one without editing hundreds of class.
Edit:
Even better would be inheritence of meta annotations for example:
#autoEquatable
#immutable
#jsonSerializable
class LoginEvent {}
And all of the sub classes have those annotations to. Is something like this possible?

Typescript- Using class as interface, why do I have to implement private members/methods?

I'm using the Mixin pattern as illustrated below. Why does Typescript require you to provide stand-in properties for private properties of the mixin class in the target class (A)? It perfectly makes sense for the public properties, but for private properties it unnecessarily crufts up the target class with details of the internal implementation of the mixin class by requiring them to be stubbed-out in the target class. Seems like the Typescript transpiler should be able to not require this.
class Mixin {
private foo:string;
}
class A implements Mixin {
// stand-in properties, typescript requires even
// private properties to be stubbed-out
foo:string;
}
Private members contribute to the structure of a type in TypeScript, so if you don't implement them you are not compatible with the type. This actually makes it impossible to match a type structurally in TypeScript if it has a private member, because you are either:
a. Failing to provide the type
or
b. Providing a separate implementation of the private member
So you can only extend a type with a private member, not implement it.
With this in mind, you are better off not using private members with mixins. Provide the ghost-members in the implementation class and keep your fingers crossed that if mixins gain some traction the ghosting will become unnecessary (see TypeScript mixins part one).