开发者

Why can Dart's built-in List interface be instantiated?

开发者 https://www.devze.com 2023-04-12 17:08 出处:网络
Notice: This question is obsolete; the interface declaration syntax has been removed from Dart: Proposal to eliminate interface declarations from Dart

Notice: This question is obsolete; the interface declaration syntax has been removed from Dart:

  • Proposal to eliminate interface declarations from Dart

    "In Dart, every class engenders an implicit interface. Now that this feature is implemented, it is possible to actually eliminate interface decla开发者_如何学编程rations from the language. Interface declarations are replaced by purely abstract classes."

  • Issue 3972: Remove interface declaration support in VM


As far as I've been able to tell, it's impossible to instantiate an interface in Dart. If I simply try to construct a new MyInterface(), with or without a constructor defined, I get a run-time error (try it):

NoSuchMethodException - receiver: '' function name: 'MyInterface$$Factory' arguments: []]
interface MyInterface {}      
interface MyInterface {
  MyInterface();
}

If I try to use a factory constructor instead, returning an instance of an implementation, I get a compile-time error (try it):

SyntaxError: factory members are not allowed in interfaces
class MyImplementation implements MyInterface {
  MyImplementation();
 }

interface MyInterface {
  factory MyInterface() { return new MyImplementation(); }
}

However, this seems at-odds with the reality that List<E>1 in Dart's core library is an interface2, yet it has several constructors and can be instantiated. For example, this works fine (try it):

main() {
  var list = new List();
  list.add(5);
  print(list.last());
}

Why can List and many other built-in interfaces be instantiated? Is there some method I missed or are they just receiving special treatment as built-in types?


1 Dart: Libraries: corelib: interface List<E>

2 "Much of the Dart Core Library is defined in terms of interfaces."3

3 Dart: Tutorial: Interfaces


The syntax for defining an interface is:

interfaceDefinition:
    interface identifier typeParameters? superinterfaces? factorySpecification? `{' (interfaceMemberDefinition)* `}'

Notice that the factorySpecification must come before the body of the interface rather than inside it.

So this is how you write it:

interface MyInterface default MyImplementation {

}

class MyImplementation implements MyInterface {
  MyImplementation();
}

Or if you want to go for the full generic definition:

interface MyInterface<E> default MyImplementation<E> {
    MyInterface(x);
}

class MyImplementation<E> implements MyInterface<E> {
  MyImplementation(this.x);
  E x;
}

Edit: For a more complete example, you can read the source code for the interface List<E> at https://code.google.com/p/dart/source/browse/branches/bleeding_edge/dart/corelib/src/list.dart and the associated class ListFactory<T> source is at https://code.google.com/p/dart/source/browse/branches/bleeding_edge/dart/runtime/lib/array.dart


Dart uses factory for two different things: factory classes, and factory constructors. A factory class looks like this:

interface List default ConcreteList {
  List();
  ...
}

class ConcreteList implements List {
  ConcreteList() {}
}

What this does is it lets you define constructors in an interface. When you invoke them by doing new List() (or whatever your interface is), it knows to actually instantiate ConcreteList because that's the factory class you've specified for that interface.

This gives you a way to completely encapsulate a concrete type behind an interface, including even the point of construction.

A factory constructor looks like this:

class Point {
  static _zero;
  int x, y;

  Point(this.x, this.y) {}

  factory Point.zero() {
    if (_zero == null) _zero = new Point(0, 0);
    return _zero;
  }
}

Here, Point.zero is a (named) factory constructor. Factory constructors let you abstract instantiation. You invoke them like a regular constructor, but they don't automatically generate a new instance of the object. Instead, you're free to do whatever you want in the body of the constructor. Here, every time you do:

new Point.zero();

You will get the same cached _zero object, even though you're using new each time because they factory constructor always returns the same one. They have a couple of uses:

  1. Returning previously cached objects like we're doing here.
  2. Returning a subclass. This is kind of like a factory class for a interface. You may have a class that you can new but under certain circumstances you may actually want to return a subclass of it in order to specialize its behavior. Factory constructors let you do that without having to change the callsite.
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号