GithubHelp home page GithubHelp logo

dep-external-libraries's People

Contributors

munificent avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

kevmoo

dep-external-libraries's Issues

When is a Client a Client?

// oauth.dart

import 'package:http/http.dart'

Future authenticate(Client cleant) { ... }

We could imagine that io_client.dart, besides providing an implementation of Client also provides IoClient extends Client with io-specific features.

// my vm code

import 'package:http/io_client.dart';

import 'oauth.dart';

void main() {
  var client = new IoClient(cookieStore: 'cookies.cks');
  authenticate(client); // is this a type warning?  
}

The Client in io_client.dart has no relationship to Client in http.dart – at least not in the URI rules we think of in Dart today.

Optional annotation on external library to specify which canonical library it is implementing

// warn.dart
external library 'warn_browser.dart' for dart.html;
external library 'warn_console.dart' for dart.io;

/// Warns the user about [message].
external void warn(String message);

We'll call this the canonical library. It in turn refers to two separate
external libraries:

// warn_browser.dart

external export 'warn.dart'; // reusing export is intentional

import 'dart:html';

void warn(String message) {
  html.document.body.appendHtml('<div class="warn">$message</div>');
}

This allows the analyzer to help with missing/incorrect implementations of the canonical library.

It's analogous to part and part of.

The use of export is intentional. If the canonical library defines types, they should be 100% compatible with the types defined by the external library.

It could also help facilitate runtime replacing libraries for testing – where the canonical library doesn't "know" it will be replaced, but you want tooling for a mock implementation.

Is it allowed to have several externalLibrary ?

In Linking to external libraries:

A canonical library can wire itself up with zero or more external libraries using an external library directive

I understand more as >=1 but in the definition of libraryDefinition I see:

libraryDefinition:
  scriptTag? libraryName? (externalLibrary|externalForLibrary)? importOrExport* partDirective* topLevelDefinition*
  ;

If I understand correctly that means 0 or 1 externalLibrary.

So is it allowed to have several external libraries ?


In the context of source gen it's likely that several external lib could be used (Eg. one for JSON, one for identity(hashcode / .==), one for toString()) Moreover those external libraries would define only some of all the external members of a class from the canonical lib.

Here is an example:

person.dart
external library 'person-json.g.dart';
external library 'person-identity.g.dart';
external library 'person-tostring.g.dart';

class Person {
  final String name;

  Person(this.name);

  external Person.fromJson(Map json);
  external Map toJson();

  external int get hashCode;
  external bool operator ==(o);
  external String toString();
}
person-json.g.dart
external library for 'person.dart';

import 'dart:convert';

class Person {
  factory Person.fromJson(Map json) => new Person(json["name"]);
  Map toJson() => {"name": name};
}
person-identity.g.dart
external library for 'person.dart';

import 'dart:convert';

class Person {
  int get hashCode => hashObjects([name]);
  bool operator ==(o) => identical(this, o) || o.runtimeType == runtimeType && o.name == name;
}
person-tostring.g.dart
external library for 'person.dart';

import 'dart:convert';

class Person {
  String toString() => "Person(name=$name)";
}

Is it a valid usage of external libraries (particularly partial patches) ?

library extension feature?

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 like abstract, 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)

Use external part instead of external library

How about

external part 'warn_browser.dart' for dart.html;
external part 'warn_console.dart' for dart.io;

instead of

external library 'warn_browser.dart' for dart.html;
external library 'warn_console.dart' for dart.io;

I don't always want an identical API across platforms

This produces worse UI for some existing packages' use cases than either Søren's original proposal or Lasse's proposal. There are places where we actively want to have a few platform-specific APIs in an otherwise platform-independent package, and we want to make these APIs visible to the analyzer and easy to use—I don't want http to be less usable for server-only developers because it also happens to support the browser. If it's less usable, that incentivizes the creation and use of less portable but more usable packages, which fragments the ecosystem.

In http, we want to support a cross-platform Client class like the one in your example, for which this works well. However, we also want to have user-visible BrowserClient and IoClient classes that support more powerful platform-specific APIs, such as configuring behavior for bad SSL certificates on the server or auto-parsing the response on the browser. Under this proposal, the only options for this are to either leave the APIs untyped or move any APIs with platform-specific annotations into a separate library requiring a separate import, which isn't much better than the status quo. In fact, it's worse: currently if you import package:http/http.dart on the server, you do get access to IoClient, thanks to a small use of dart:mirrors.

The glob package is another good example. It's API is based on the Glob class; the usual pattern of use is to call new Glob.parse once for a given pattern and then re-use that pattern to save parse and compile time, much like the pattern for RegExp. A Glob can be used for two things: matching paths and listing filesystem entities whose paths match the pattern. The former is entirely platform-independent, while the latter is clearly limited to the server. But Glob.list returns a Stream<FileSystemEntity>, which can't be represented under this proposal.

This is an even worse case than http, since it's important that Glob.list be an instance method of Glob both for usability and for performance, so it can re-use the compiled representation. That rules out putting it in a separate library, so the only option is to remove the type platform-specific type annotations, producing a degraded user experience, especially for IDE users.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.