4

I'm implementing an inheritance hierarchy in which derived-class construction consists only of a call to the base-class constructor. The base-class constructor then calls method(s) implemented only in the derived-class.

I have a basic implementation, but DartEditor of course complains about the missing methods in the base class. How can I make it happy?

Edit: I hadn't yet ran any code before posting my question, and it turns out that method binding works in the manner one would expect:

void main() {
    new B();
}

abstract class A {
    A() {
        x();
        y();
    }
    x() => print('A.x');
    y() => print('A.y');
}

class B extends A {
    B() : super();

    @override
    x() => print('B.x');
}

The above code outputs the following, which is the desired behavior. B's constructor calls A's constructor which calls x(). But since there is an x() defined for B, this is the one called:

B.x
A.y

It interesting to note that, although x() is being called by A's constructor, Dart somehow knows to call B's x(). I presume this is because the call chain looks roughly like the following:

B() -> A() -> B::x()

At runtime, Dart inspects the call chain to determine to which object to bind x().

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
Tom Russell
  • 1,015
  • 2
  • 10
  • 29
  • 1
    Hard to tell without seeing any concrete code that shows what you try to accomplish or any concrete error message. – Günter Zöchbauer Jun 15 '15 at 22:24
  • This is normal object-oriented behavior. If you override a method in the derived class this method is called instead (called dynamic binding). You can explicitly call the method of the base class from the derived class like `super.x();` for example to reuse the base implementation. – Günter Zöchbauer Jun 16 '15 at 20:39
  • Thanks. Even the part about the call to x() in A() binding to B::x()? – Tom Russell Jun 17 '15 at 08:50
  • Sure. The code in `A.x()` was originally implemented in `A` but even when the code is invoked from code implemented in `A` the current instance is actually a `B` and therefore the method of `B` is called. (In my previous comment it should be "dynamic dispatch" instead of "dynamic binding") – Günter Zöchbauer Jun 17 '15 at 08:59
  • Thanks. This has been very helpful. Is there a way to remove the implementation of x() in A altogether? – Tom Russell Jun 17 '15 at 17:46
  • If you want to call or just reference `x()` from code in `A` it must exist. The minimum requirement if `A` is abstract is the declaration `x();` (see my first example in my answer). To work around this limitation you can add the `@proxy` annotation like I did in my answer in the 2nd example. This can have negative side-effects though (code bloat) when built to JS because this requires mirrors (reflection). – Günter Zöchbauer Jun 17 '15 at 17:54
  • Would @proxy prevent *any* implementation in A? The code bloat thing is a good one to look out for... – Tom Russell Jun 17 '15 at 18:09
  • `@proxy` doesn't prevent implementation, it just allows to call methods which are actually not there statically and indicates to the analyzer/VM that it should ignore their absence. – Günter Zöchbauer Jun 17 '15 at 18:15

1 Answers1

3

From your question I would expect code like this

void main() {
 new B();
}

abstract class A {
  A() {
    a();
    b();
    c();
  }
  a();
  b();
  c();
}

class B extends A {
  B() : super();

  @override
  a() => print('a');
  @override
  b() => print('b');
  @override
  c() => print('c');
}

Try in DartPad

From your comment about getting an error I expect you don't have the abstract method stubs in the base class. Maybe this is what you are looking for

void main() {
 new B();
}

@proxy
abstract class A {
  A() {
    a();
    b();
    c();
  }
}

class B extends A {
  B() : super();

  a() => print('a');
  b() => print('b');
  c() => print('c');
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567