library extension feature?
jmesserly opened this issue · comments
I was playing around with this, but slicing it a little differently:
- library extensions: the idea that we "extend" a library
- some way of configuring which library extension to load in place of an existing one
Here's a sketch of how it would look for package:html:
Key concepts:
external
is likeabstract
, but for libraries@patch
is an annotation like@override
. It is optional but provides documentation/checking.- you can give a prefix for the library being extended, this is like
super
- in this sketch, both libraries and each of their types (the "base" and "impl") would show up in reflection.
I think the current proposal "merges" the libraries and types at runtime. That's probably a simpler/better approach, this is just illustrating an alternative.
package:html/html.dart:
// We'd like to provide different implementations for a library
// (e.g. server ane browser), while preserving the same API structure.
// The proposal is to handle this similar to "patch" files already used for
// this in the core libraries. It accomplishes this by using "library extensions".
// external is like "abstract", but for the whole library
external library dart.html; // html.dart
external abstract class Node {
external Node parentNode, firstChild, lastChild, nextNode, previousNode;
Element get parent => parentNode is Element ? parentNode : null;
List<Node> childNodes => new _ChildNodeList(this);
}
external abstract class Element extends Node {
external factory Element.html(String html);
external factory Element.tag(String tag);
external String get localName;
}
package:html/src/standalone_html.dart:
// declares a library extension, and gives a name to the base library.
library dart.html_standalone extends 'package:html/html.dart' as base;
// @patch is like @override but for the library. Optional. Runtime will ignore.
@patch
class Node extends base.Node {
Node();
}
// Extend base.Element, which then extends our overridden "Node".
// Alternatively `extends Node`, and have the relationship to `base.Element` be implied,
// If we "merge" libraries, this becomes a non-issue: `extends Node` wouldn't even need to
// be repeated.
@patch
class Element extends base.Element {
@patch
factory Element.html(String html) {
// ... parse HTML stand such ...
}
Element(this.localName);
final String localName;
//...
}
package:html/src/browser_html.dart
library dart.html_browser extends 'package:html/html.dart' as base;
// The browser's view of HTML libs...
user code:
// Now, we just need a way to indicate to the runtime which extension to use, so
// user can write:
import 'package:html/html.dart'; // loads the appropriate extension.
// This can be accomplished through the package spec:
// dart --package-spec
Anyway, not sure we should slice it this way, but maybe it's another perspective for discussion.
Regardless, would it be worth a pull request for the HTML example? (but modified to match the existing proposal's syntax/semantics)
+1 to the concept of declaring a library abstract (via external) and declaring another library to extend it!
I'm not sure that using the package spec for platform-specific library selection can work. Nobody would want to build the package spec manually. And to build it automatically, the base libraries would need to contain the information about which sub-libraries to use on which platforms. And then the code would need to be analyzed before it is run in order to build the package spec.
Unless platform specific libraries were kept in a strict conventional location with respect to the base library, in which case the package spec could be deduced from the file system.