The following code comes from the language tour
class Musician {}
mixin MusicalPerformer on Musician {}
class SingerDancer extends Musician with MusicalPerformer {}
Docs says:
In the preceding code, only classes that extend or implement the Musician class can use the mixin MusicalPerformer.
However, if I do the implements part, I get a compile error:
class SingerDancer implements Musician with MusicalPerformer {} // Compile error
When you mix-in a mixin, the superclass of the mixin application must implement the on requirements of the mixin. The superclass is the class before the with.
The class SingerDancer extends Musician with MusicalPerformer {} works because the superclass, Musician, implements (trivially) the interface Musician, and therefore you can apply MusicalPerformer to it.
If you have a class:
class SingerDancer implements Musician { ... }
then you can apply MusicalPerformer to it:
class SingerDancerPerformer = SingerDancer with MusicalPerformer;
However, when you write:
class SingerDancer implements Musician with MusicalPerformer {}
the parts are in the wrong order. If it was allowed, it would perhaps mean
class SingerDancer with MusicalPerformer implements Musician {}
aka.
class SingerDancer extends Object with MusicalPerformer implements Musician {}
(If you omit the extends X before with it's implicitly extends Object, just as if you omit extends X on a class without a with).
Here the superclass of the mixin application does not implement Musician.
It's also not allowed at all because implements cannot come before extends/with in the class declaration.
The class just before the with must satisfy the requirements of the mixin (for multiple mixins, like extends X with M1, M2, the class before M2 is the mixin application X with M1).
If you want implements you should do:
class SingerPerformer implements Musician, MusicalPerformer {}
Edited:
MusicalPerfomer depends on the superclass Musician. SingerPerformer is not a subclass of Musician, but will implement its interface. So SingerPerformer cannot use the mixin, but it can implement its interface also.
Second Edit:
You can also do this:
class NewMusician implements Musician {}
class NewPerformer extends NewMusician with MusicalPerformer {}
Related
Can you have second order generics in Dart?
abstract class Foo<T, ContainerType<T>> {}
class FooList<T> extends Foo<T, List<T>> {}
Yes, and some more characters to make it 30
I think what you want is something like:
abstract class Foo<T, C extends Iterable<T>> {}
class FooList<T> extends Foo<T, List<T>> {}
(If not, try refining the question and say what you want to achieve).
I want to understand the difference between extends, implements and with. When do I use each keyword?
Extends:
Use extends to create a subclass, and super to refer to the superclass.
Extends is the typical OOP class inheritance. If class a extends class b all properties, variables, functions implemented in class b are also available in class a. Additionally you can override functions etc.
You use extend if you want to create a more specific version of a class. For example the class car could extend the class vehicle. In Dart a class can only extend one class.
Implements:
Every class implicitly defines an interface containing all the instance members of the class and of any interfaces it implements. If you want to create a class A that supports class B’s API without inheriting B’s implementation, class A should implement the B interface.
Implements can be used if you want to create your own implementation of another class or interface. When class a implements class b. All functions defined in class b must be implemented.
When you're implementing another class, you do not inherit code from the class. You only inherit the type. In Dart you can use the implements keyword with multiple classes or interfaces.
With (Mixins):
Mixins are a way of reusing a class’s code in multiple class hierarchies.
With is used to include Mixins. A mixin is a different type of structure, which can only be used with the keyword with.
They are used in Flutter to include common code snippets. A common used Mixin is the SingleTickerProviderStateMixin.
extend can only be used with a single class at the time, BUT... you can easily extend a class which extends another class which extends another class which...! ;)
In fact, most Flutter widgets are already built like that.
On a flutter example project I stumbled upon those lines:
abstract class BlocEvent extends Object {}
abstract class BlocState extends Object {}
abstract class BlocEventStateBase<BlocEvent, BlocState> {}
Is this a class based on map? or maybe class with two types?
What is the meaning of <BlocEvent, BlocState>?
It's a generic type declaration, but as #yelliver pointed out, the example you posted is not correct, since BlocEvent and BlocState inside <> are just interpreted as generic type identifiers (unrelated to the classes with the same name).
This would make sense:
abstract class BlocEvent extends Object {}
abstract class BlocState extends Object {}
abstract class BlocEventStateBase<T extends BlocEvent, S extends BlocState> {}
Also, note that there are conventions for naming type parameters.
I wonder if there is the possibility to dynamically extend a class, I'm new to Dart and I'm looking for something like this (please forget about the ${whatever} is just for illustration purposes):
class MyClass extends ${otherClass}
and let's say I'm trying to instantiate it from another function:
var myDinamic = new myClass<otherClass>
Hope this makes sense and thanks in advance!
In short: No.
Dart requires all classes to have a single superclass. What you are asking for is having a single class that changes its superclass per instance. That's not really a single class - it's impossible to say which members that class has because it is really a different class for choice of superclass.
That a class extends another class can only be defined statically but not at runtime. The closest to that is probably configuring types with generic type arguments.
See also
- https://www.dartlang.org/docs/dart-up-and-running/ch02.html#generics
- http://blog.sethladd.com/2012/01/generics-in-dart-or-why-javascript.html
abstract class SomeInterface {}
class A implements SomeInterface {}
class B implements SomeInterface {}
class C<T extends SomeInterface> {
T doSomething(T arg) { return arg; }
}
main() {
new C<A>();
new C<B>();
// does NOT work
// var t = A;
// new C<t>();
}
but type arguments also need to defined statically. You can't use a variable as generic type argument.
i want to do something like the following so bad
abstract class A{}
abstract class B extends A{}
abstract class C extends A{}
abstract class D extends B with C{} //C cannot be used as a mixin because it extends a class other than object
is there any solution other than copying the content of C in D?
the real names of my classes, to give you an idea of what i am trying to do
//A Observable
//B DynamicObservable
//C ObservableWithValidationErrors
//D DynamicObservableWithValidationErrors
There are some restrictions on the class you can use as mixin (See Mixins in Dart - Syntax and semantics).
However, in this proposal, a mixin may only be extracted from a class that obeys the following restrictions:
The class has no declared constructors.
The class’ superclass is Object.
The class contains no super calls.
Those restrictions may be removed in the future.
The semantics are deliberately restricted in several ways, so as to reduce disruption to our existing implementations, while allowing future evolution toward a full-fledged mixin implementation. This restricted version already provides considerable value.
In some circumstances it might be possible to restructure your class to use multiple mixins instead:
abstract class Observable{}
abstract class Dynamic{}
abstract class ValidationErrors{}
abstract class DynamicObservable extends Observable with Dynamic{}
abstract class ObservableWithValidationErrors extends Observable with ValidationErrors{}
abstract class DynamicObservableWithValidationErrors extends Observable with Dynamic, ValidationErrors{}
Of course, if Dynamic or ValidationErrors cannot be isolated this way, and rely on inheriting from Observable, this will not be possible.