lrhn / dep-configured-imports

Dart Enhancement Proposal for Configurable Imports.
8 stars 1 forks source link

extending expression language to handle package versions #11

Open sigmundch opened 9 years ago

sigmundch commented 9 years ago

We've been thinking about a problem for which configured imports could be an important piece of the solution. However, to be useful we would need a more expressive expression language to choose which import to load.

Motivation

The problem I'd like to address it to reduce cascading effects that occur when versioning package dependencies. Here is an example: Say package A and C have a dependency on package B and a new version with breaking changes comes along for B. Developers of A and C today must pick to stay in the old version of B or move to the new version. If A and C developers pick differently, users will have trouble using A and C together in their apps.

One way to address this problem is to let developers use either version of B. We could do so with configured imports if, say, there is a user defined configuration with the version of the packages it uses:

import analyzer.package.version == "0.22.0" : "some uri.dart"
    || "default uri.dart"
    deferred as foo show x hide y;

(let's put aside how to determine what the current version is to set analyzer.package.version, since that is less relevant to the discussion of configured imports here).

The challenge for configured imports though, is that the expression language for tests is not expressive enough to write more complex version constraint tests. For example, it's important to be able to select a version range, like:

import analyzer.version in ">= 0.22.0 <0.23.0" : "uri.dart"
    || "default uri.dart"
    deferred as foo show x hide y;

Ideas

I think that adding general support for boolean expressions might be too expressive for this (even if they are limited to const objects defined in non-configured libraries).

An option is to add special support for version constraints. They are a key part of the Dart ecosystem and definitions for constraints could be exposed either in the import syntax or as const definitions in a dart: library. This example treats it as part of the language:

import analyzer.version in ">= 0.22.0 <0.23.0" : "uri.dart"

alternatively we could do:

import 'dart:constraints';
import const VersionRange(">= 0.22.0 <0.23.0").contains(analyzer.version) : "uri.dart"

or

import analyzer.version.inRange(">= 0.22.0 <0.23.0") : "uri.dart"