KOGI KOGI - 1 month ago 8
Dart Question

How to properly proxy "inherited" static methods?

I'm pretty new to Dart and still learning all the nuances it brings. One thing I'm really getting hung up on with my current task is inheriting (or proxying) static methods from a parent class.

void main() {
EnglishCasual.greet();
}

class English {
static greet() {
actGreeting();
sayGreeting();
}

static sayGreeting() {
print('hello');
}

static actGreeting() {
print('<tips hat>');
}
}

class EnglishCasual extends English {
static sayGreeting() {
print("m'lady");
}

static actGreeting() {
print('<tips fedora>');
}
}


The above gives the error
NoSuchMethodError: method not found: 'greet'
, which, according to the Dart docs, is expected behavior, since static methods are not inherited (which seems odd to me, but ok. moving on...)

So then I tried a simple proxy to the parent class...

DartPad Example

But that yields another error:
Invalid context for 'super' invocation
or
'super' is only available in instance methods
. Ok... let's explicitly call the parent class by name.

DartPad Example

But, as expected, that's just treated as any other call to
English.greet()
and we get a formal greeting instead of a casual one. Makes sense.

So then I turned to reflection. I found a snippet here on SO that seemed promising and put it to the test:

DartPad Example

Which resulted in an error
The method 'greet' is not defined for the class 'EnglishCasual'
, which I should have expected, since
noSuchMethod
wasn't defined as static, it wasn't getting called for static method calls. So, one last time...

DartPad Example

And we get another error
The name 'noSuchMethod' is already defined in 'core/object.dart'
.

At this point, I'm out of ideas. It seems that there is no way to accomplish this (seemingly simple) exercise, and I'm really hoping you guys can point me in the right direction.

What's the correct way to do this?

lrn lrn
Answer

As you say, static methods are not inherited. That means that only instance methods are inherited. The only ways you can call two different functions with one call operation is if:

  • it's invoking an instance method (incl. getters, setters and operators), or
  • it's invoking a function value.

That is:

callA(o) => o.foo(42);  // Instance method.
callB(f) => f(42);  // Function value.

In all other situations, the function to call is determined statically, so you will always call exactly the same function. You can't make your greet function call different functions depending on how it's called unless it's an instance method itself or it takes a parameter that helps it choose.

In other words, don't try to do clever stuff with static functions. You are trying to have the CasualEnglish versions of sayGreeting and actGreeting override the ones in English. That can only work if they are instance members.