Is it possible to call a second ancestor method in dart? something like super.super.hello()? If it's possible, how can it be written?
class A {
void hello() {
print('A');
}
}
class B extends A {
#override
void hello() {
print('B');
}
}
class C extends B {
#override
void hello() {
// How to call the hello() implemented in the class A here?
}
}
void main() {
var c = C();
c.hello();
}
It's not possible.
The reason it's not possible is that it breaks abstraction.
When you look at class C extend B, all you need to know about B is which signatures its members has and which interfaces it implements. As long as that stays effectively the same, your valid code will keep working.
Consider what would happen if the author of B decided to make themselves a helper base-class:
abstract class _BaseB extends A {
String get _myName;
#override
void hello() {
print(_myName);
}
}
class B extends _BaseB {
#override
String get _myName => "B";
}
That's a perfectly valid refactoring. The resulting class B has all the same members and implements all the same interfaces (and also _BaseB, but it's private so nobody can see that).
The C class above would keep working if all it does is to call super.hello(). If it had a way to ask for super.super.hello(), that might no longer be valid.
Similarly if the B class was changed to:
class B implements A {
#override
void hello() {
print("B");
}
}
(changing extends to implements), then all methods of B works the same as before and it implements the same interfaces. Again, there is no visible differences to the users of the B class.
But if you could call something like A.super.hello() to reach the A class's hello method, then that would now break because that method isn't in the B class at all.
So, by restricting super.hello() to only call methods on the precise class you write as the superclass, you are prevented from introducing dependencies on the implementation of B, dependencies which would make otherwise valid refactorings into breaking changes.
Related
I am learning Dart and am facing an issue with understanding the way inheritance works here.
I have 3 classes Alphabet, A which extends Alphabet and B which extends Alphabet and implements A. Something like this:
class Alphabet {
void define() {
print("this is an alphabet");
}
}
class A extends Alphabet {
void func1() {
print("called func1");
}
void func2() {
print("called func2");
}
}
class B extends Alphabet implements A {
#override
void func1() {
print("called B:func1");
}
#override
void func2() {
print("called B:func2");
}
}
Now, the problem is this works, even though I haven't defined the define() function from A, the function that A inherits from Alphabet.
My questions are :
In class B, which define() function do I get, A.define() or Alphabet.define()?
And if the define() function that I get is from Alphabet, then doesn't it defeat the purpose of implementing a class? As class A has 2 of its own functions and one that it inherits from Alphabet. So, it should tell me to override 3 functions.
NOTE: When I remove extends Alphabet from the definition class B, it shows the expected behavior, saying that I need to implement the define() function. That makes sense.
When you write B extends Alphabet, that means that B provides the interface of Alphabet and inherits the implementation of Alphabet.
When you write B implements A, that means that B provides the interface of A but does not use any of A's implementation.
B extends Alphabet implements A does what you requested: it provides the interfaces of both Alphabet and A (and the interface of A is a superset of Alphabet's), and it uses the implementation from Alphabet but not from A. B.define() therefore will call the Alphabet.define implementation.
And if the define() function that I get is from Alphabet, then doesn't it defeat the purpose of implementing a class? As class A has 2 of its own functions and one that it inherits from Alphabet. So, it should tell me to override 3 functions.
No. If it worked that way, then it would defeat the purpose of extends A. If you want to force B to override all of the functions provided by A's interface, then simply write B implements A.
How can I have an abstract private method in dart?
// person.dart
abstract class Person{
void _walk(); //Abstract Method
void _talk(); //Abstract Method
}
// jay.dart
import "person.dart";
class Jay extends Person{
#override
void _walk() {
print("Jay can walk");
}
#override
void _talk() {
print("Jay can talk");
}
}
I want to hide _walk and _talk from Jay instance
package:meta provides a #visibleForOverriding annotation that might do what you want. Note that violating it will generate only an analysis warning, and it won't be enforced at runtime.
Personally I think that putting things that are meant to be private in the abstract base class is a bad idea since they shouldn't be part of the interface. Consider instead doing:
abstract class Person {
...
}
abstract class _Person extends Person {
void walk();
void talk();
}
and now your library can internally derive classes from _Person and use walk and talk, and they won't be exposed at all to external consumers of your library.
I am trying abstract classes I found one issue that I have to implement the non-abstract method having a body in child classes
code:
abstract class Animal{
void breathe(); //abstract method
void makeNoise(){
//non abstract method
print('making animal noises!');
}
}
abstract class IsFunny{
void makePeopleLaugh();//abstract method
}
class TVShow implements IsFunny{
String name;
#override
void makePeopleLaugh() {
// TODO: implement makePeopleLaugh
print("TV show is funny and make people laugh");
}
}
class Comedian extends Person implements IsFunny{
Comedian(String name, String nation) : super(name, nation);
#override
void makePeopleLaugh() {
// TODO: implement makePeopleLaugh
print('make people laugh');
}
}
class Person implements Animal{
String name,nation;
Person(this.name,this.nation);
//we must implement all the methods present in Abstract class and child should override the abstract methods
#override
void breathe() {
// TODO: implement breathe
print('person breathing through nostrils!');
}
//there should be no compulsion to override non abstract method
#override
void makeNoise() {
// TODO: implement makeNoise
print('shouting!');
}
}
void main(List arguments) {
var swapnil=new Person('swapnil','India');
swapnil.makeNoise();
swapnil.breathe();
print('${swapnil.name},${swapnil.nation}');
}
here I am trying not to implement makeNoise method in my Person class but it gives error and says abstract method must be implemented.
Is this bug or I am getting concept wrong
You are using implements, which is used for interfaces, not for inheritance. The keyword you are looking for is extends.
abstract class Foo {
void doThing() {
print("I did a thing");
}
void doAnotherThing();
}
class Bar extends Foo {
#override
void doAnotherThing() {
print("I did another thing");
}
}
I don't believe this is a bug. The method is still in an abstract class that you are implementing. I think that you instead intended to extend the class in which case you would call super.makeNoise() in the override.
I figured out the solution after some time I understood that when inheriting abstract class I should have used extends keyword instead of implements due to which dart was telling me to also implement the non-abstract method as it is compulsory to implement all methods when using interfaces.
I think my question was silly
I have the following code:
class A {
void m() {
print("hello");
}
}
mixin B {
void m() {
print("mixin class b");
}
}
class C extends A with B {
void m() {
print("m of c");
super.m();
}
}
void main() {
C cc = C();
cc.m();
}
Here when I write super.m() it is referring to the mixin class rather than m() of class A, why? Which exactly is its superclass referenced by super.
How can I then call m() of class A from C?
I don't think it is possible to get the m method on A in your example. The reason is by using mixins you are telling the compiler you want to extend A but please insert all methods from B even if one of the methods overrides an existing one. So after compile, the compiled class of C ends up not even containing A.m.
There are some details about this behavior in this older article and with some explanation about why this is the case: https://medium.com/flutter-community/https-medium-com-shubhamhackzz-dart-for-flutter-mixins-in-dart-f8bb10a3d341
A few times now I've run into a use case where I need to define an interface for how classes construct themselves. One such example could be if I want to make an Interface Class that defines the interface by which objects can serialize and unserialize themselves (for input into a database, to be sent as JSON, etc). You might write something like this:
abstract class Serializable {
String serialize();
Serializable unserialize(String serializedString);
}
But now you have a problem, as serialize() is properly an instance method, and unserialize() should instead be a static method (which isn't inheritable or enforced by the Interface) or a constructor (which also isn't inheritable).
This leaves a state where classes that impliment the Serializable interface are required to define a serialize() method, but there is no way to require those classes to define a static unserialize() method or Foo.fromSerializedString() constructor.
If you make unserialize() an instance method, then unserializing an implementing class Foo would look like:
Foo foo = new Foo();
foo = foo.unserialize(serializedString);
which is rather cumbersome and ugly.
The only other option I can think of is to add a comment in the Serializable interface asking nicely that implementing classes define the appropriate static method or constructor, but this is obviously prone to error if a developer misses it and also hurts code completion.
So, is there a better way to do this? Is there some pattern by which you can have an interface which forces implementing classes to define a way to construct themselves, or something that gives that general effect?
You will have to use instance methods if you want the inheritance guarantees. You can do a bit nicer than manual instantiation though, by using reflection.
abstract class Serializable {
static Serializable fromSerializedString(Type type, String serializedString) {
ClassMirror cm = reflectClass(type);
InstanceMirror im = cm.newInstance(const Symbol(''), []);
var obj = im.reflectee;
obj.unserialize(serializedString);
return obj;
}
String serialize();
void unserialize(String serializedString);
}
Now if someone implements Serializable they will be forced to provide an unserialize method:
class Foo implements Serializable {
#override
String serialize() {
// TODO: implement serialize
}
#override
void unserialize(String string) {
// TODO: implement unserialize
}
}
You can get an instance like so:
var foo = Serializable.fromSerializedString(Foo, 'someSerializedString');
This might be a bit prettier and natural than the manual method, but keep in mind that it uses reflection with all the problems that can entail.
If you decide to go with a static method and a warning comment instead, it might be helpful to also provide a custom Transformer that scans through all classes implementing Serializable and warn the user or stops the build if any don't have a corresponding static unserialize method or constructor (similar to how Polymer does things). This obviously wouldn't provide the instant feedback the an editor could with instance methods, but would be more visible than a simple comment in the docs.
I think this example is a more Dart-like way to implement the encoding and decoding. In practice I don't think "enforcing" the decode signature will actually help catch bugs, or improve code quality. If you need to make the decoder types pluggable then you can make the decoders map configurable.
const Map<String,Function> _decoders = const {
'foo': Foo.decode,
'bar': Bar.decode
};
Object decode(String s) {
var obj = JSON.decode(s);
var decoder = _decoders[obj['type']];
return decoder(s);
}
abstract class Encodable {
abstract String encode();
}
class Foo implements Encodable {
encode() { .. }
static Foo decode(String s) { .. }
}
class Bar implements Encodable {
encode() { .. }
static Foo decode(String s) { .. }
}
main() {
var foo = decode('{"type": "foo", "i": 42}');
var bar = decode('{"type": "bar", "k": 43}');
}
A possible pattern I've come up with is to create a Factory class that utilize instance methods in a slightly less awkward way. Something like follows:
typedef Constructable ConstructorFunction();
abstract class Constructable {
ConstructorFunction constructor;
}
abstract class Serializable {
String serialize();
Serializable unserialize(String serializedString);
}
abstract class SerializableModel implements Serializable, Constructable {
}
abstract class ModelFactory extends Model {
factory ModelFactory(ConstructorFunction constructor) {
return constructor();
}
factory ModelFactory.fromSerializedString(ConstructorFunction constructor, String serializedString) {
Serializable object = constructor();
return object.unserialize(serializedString);
}
}
and finally a concrete implementation:
class Foo extends SerializableModel {
//required by Constructable interface
ConstructorFunction constructor = () => new Foo();
//required by Serializable interface
String serialize() => "I'm a serialized string!";
Foo unserialize(String serializedString) {
Foo foo = new Foo();
//do unserialization work here to populate foo
return foo;
};
}
and now Foo (or anything that extends SerializableModel can be constructed with
Foo foo = new ModelFactory.fromSerializedString(Foo.constructor, serializedString);
The result of all this is that it enforces that every concrete class has a method which can create a new instance of itself from a serialized string, and there is also a common interface which allows that method to be called from a static context. It's still creating an extra object whose whole purpose is to switch from static to instance context, and then is thrown away, and there is a lot of other overhead as well, but at least all that ugliness is hidden from the user. Still, I'm not yet convinced that this is at all the best way to achieve this.
I suggest you define the unserialize function as named constructor like so:
abstract class Serializable<T> {
String serialize();
Serializable.unserialize(String serializedString);
}
This eliminates the need of static methods.
A possible implementation could look like this:
import 'dart:convert';
class JsonMap implements Serializable<JsonMap> {
Map map = {};
JsonMap() {
}
String serialize() {
return JSON.encode(map);
}
JsonMap.unserialize(String serializedString) {
this.map = JSON.decode(serializedString);
}
}
You can (de)serialize like so:
JsonMap m = new JsonMap();
m.map = { 'test': 1 };
print(m.serialize());
JsonMap n = new JsonMap.unserialize('{"hello": 1}');
print(n.map);
While testing this, I noticed that Dart will not throw any errors at you if you dont actually implement the methods that your class promises to implement with implements. This might just be a hicc-up with my local Dart, though.