7

Is there a way to avoid inheritance in Dart? I'm looking for something like

final class MyJavaClass {
    ...
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
Mike Mitterer
  • 6,810
  • 4
  • 41
  • 62
  • What are you trying to achieve by preventing inheritance? – Alan Knight Feb 05 '14 at 04:11
  • 2
    Simple sample is ApiCredentials - makes no sense to inherit something from this class. – Mike Mitterer Feb 05 '14 at 09:56
  • If it makes no sense, then presumably people won't do it. But jumping through these kind of hoops to forcibly prevent it seems unnecessarily complicated. – Alan Knight Feb 06 '14 at 01:19
  • 3
    No, it's called defensive programming. Avoiding problems in an early stage is much cheaper than searching problems / errors at runtime. It's also a way of "useful" documentation. > then presumably people won't do it... Never! What can be done will be done :-)) – Mike Mitterer Feb 06 '14 at 08:50
  • @AlanKnight The immutability program is a very powerful and performance friendly style. Limiting classes from not being inherited is considered a good design choice under that. Wouldn't you agree? – Sisir Feb 09 '20 at 10:44

3 Answers3

7

Not directly, no.

You could write a class with private constructors and access them via static methods:

class MyFinalClass {
  MyFinalClass._ctor1() {}
  MyFinalClass._ctor2(String param1, String param2) {}
  static MyFinalClass getInstance() {
    return new MyFinalClass._ctor1();
  }
  static MyFinalClass getInstanceWithParams(String param1, String param2) {
    return new MyFinalClass._ctor2(param1, param2);
  }
}

But this has multiple problems:

  • Classes inside the same library can still subclass it - visibility in Dart applies to libraries, not single classes.
  • It's a lot of code, scaling with the amount of constructors.
  • It introduces lots of static methods, which all have to be named differently.
  • And of course, you can't instantiate the class outside its library with the new keyword.
  • This only prevents extension of a class. Implementing the "final" class is still possible.

Ultimately, these are quite a few drawbacks for this feature. It's up to you to decide if it is really worth it.

EDIT

Contrary to what I have written before, factory constructors would also work, eliminating the "unable to instantiate with new keyword" drawback.

class MyFinalClass {
  factory MyFinalClass.ctor1() {}
  factory MyFinalClass.ctor2(String param1, String param2) {}
  void method1() {}
  void method2() {}
}

Also, to illustrate why the ability to implement the not-so-final class is a big problem:

class Sub implements MyFinalClass {
  MyFinalClass _d;
  Sub.ctor1() {
    _d = new MyFinalClass.ctor1();
  }
  Sub.ctor2(String p1, String p2) {
    _d = new MyFinalClass.ctor2(p1,p2);
  }
  void method1() => _d.method1();
  void method2() {
    // do something completely different
  }
}

This pseudo-subclassing would work with the static method variant as well.

MarioP
  • 3,752
  • 1
  • 23
  • 32
4

You can add a private constructor.

class MyJavaClass {
  MyJavaClass._private();
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
0
import 'dart:mirrors';

class Final {
  Final() {
    InstanceMirror im = reflect(this);
    if (im.type.reflectedType != Final) throw "Final can't be inherited";
  }
}

class ExtendsFinal extends Final {}
//class WithFinal extends Object with Final{} //mixin can't declare constructor

void main() {
  new ExtendsFinal(); // ExtendsFinal !=  Final
}

If something implements your final class it's not a problem, because it will not inherit logic + it's really useful for testing and dependency injection.

JAre
  • 4,666
  • 3
  • 27
  • 45
  • It's not recommended to use `runtimeType`. RuntimeType can be overridden by subclasses and doesn't reliably return accurate information. Look for example at what a List returns as runtimeType. RuntimeType is mostly for debugging purposes. – Günter Zöchbauer Jun 09 '14 at 06:38
  • @GünterZöchbauer updated. Is this version sufficiently reliable for preventing unintentional breach? At least it can't be overridden. – JAre Jun 09 '14 at 13:16
  • I think so, if you want to use reflection, which should be rather avoided especially if the code runs on the client. A bigger problem is, that it catches the mistake only at runtime. Is there something you don't like about the other solutions or is this just for educational exercise? ;-) – Günter Zöchbauer Jun 09 '14 at 13:17
  • @GünterZöchbauer There is small possibility that I just search for excuse to write something 'dodgy' in Dart and get free code review, of some sort, while surfing documentation. So it won't just bounce of my skull and fly away. :P – JAre Jun 09 '14 at 13:36
  • I thought so, but cant't find something bad about it ;-) – Günter Zöchbauer Jun 09 '14 at 13:39