dartclassoopinterfacemixins

What is the point of `interface class` in Dart 3?


I have been playing around with Dart 3 a bit and am a fan of the new class modifiers. But one I can't seem to get my head around: why does interface class exist? I understand interface mixin because you can declare abstract members. But you can't do that with an interface class, at least in the latest alpha.

Specifically, you can do this:

interface mixin A {
  void foo();
}

abstract class B {
  void bar();
}

But you can't do this:

interface class C {
  void foobar(); // compilation error: needs a concrete implementation
}

What is the point of having an interface class where you will always need provide stub implementations and then implement them later on? When should you use an interface class over interface mixin?


Solution

  • This article covers a bit more details. And this question answers it more broadly.

    But the summary is, I agree with you, and that's why you should use abstract interface instead of just interface. You'd only use interface over abstract interface if you wanted to be able to instantiate it.

    abstract interface

    What is it: More like a traditional interface. Can only be implemented (not extended). But you can define functions without bodies.

    Why you should care: You can define just the “shape” without defining any functionality. There’s nothing hidden in the parent class.

    // -- File a.dart
    abstract interface class AbstractInterfaceClass {
      String name = 'Dave'; // Allowed
      void body() { print('body'); } // Allowed
      
      // This is a more traditional implementation
      int get myField; // Allowed
      void noBody(); // Allowed
    }
    
    // -- File b.dart
    // Not allowed
    class ExtensionClass extends AbstractInterfaceClass{}
    // Allowed
    class ConcreteClass implements AbstractInterfaceClass {
      // Have to override everything
      @override
      String name = 'ConcreteName';
      @override
      void body() { print('body'); }
    
      @override
      int get myField => 5;
      @override
      void noBody() => print('concreteBody');
    }
    

    vs interface

    // -- File a.dart
    interface class InterfaceClass {
      String name = 'Dave'; // Allowed
      void body() { print('body'); } // Allowed
    
      int get myField; // Not allowed
      void noBody(); // Not allowed
    }
    
    // -- File b.dart
    // Not allowed
    class ExtensionClass extends InterfaceClass{}
    // Allowed
    class ConcreteClass implements InterfaceClass{
      // Have to override everything
      @override
      String name = 'ConcreteName';
      @override
      void body() { print('body'); }
    }