-
Notifications
You must be signed in to change notification settings - Fork 227
Description
See dart-lang/sdk#60466 for context.
Sometimes you want platform specific code in the same library as general code.
You can move all platform specific code into a conditionally imported library, with a mock library with the same interface as a default, so that the code will compile on other platforms, even if the mock library code will never be run (because it's guarded by a check to ensure it'll work).
Rather than this cumbersome workaround, what if one could conditionally import a library, without a default to fall back on, so that whether that library is imported or not can be checked in the code, and so that if not, code guarded by that check won't be considered an error if it refers to names that don't exist.
Proposal:
- Allow
import if (dart.library.whatnot) "library.uri" as whatnot;- an import with no default URI, which must have a prefix name, and which must not share that prefix with any other imports (just like an deferred import). - There can be more
ifs for other cases, but if none of them are true, the import will be empty. - The prefix gets a special
isAvailablegetter (like a deferred import'sloadLibrary) which is a constant that istrueif something was imported andfalseif not. Any exported declaration of the library with that name is hidden. - Any conditional check of
prefix.isAvailableenables the prefix on thetruebranch. This is tracked the same ways as type promotion or definite-assignment, so only locally inside a function body. - If not enabled,
prefix.nameis a compile-time error. Also, extensions from the library are not available. - When enabled, if a library is actually imported during a compilation, name access is just normal import scope access. Extensions work
- When enabled, if a library was not imported, all name accesses on the prefix are allowed. The result has an unspecified meaning - like a value of type
Never, except that it can also be used as a type or class reference, and a constant, so you can writeprefix.Foo<int>.new(42)and not get an error. Basically, you can't get an error from a member access on the prefix, or downstream from that. It's dead code anyway. Also any instance member access is allowed. If it would be invalid, it's assumed to be an undefined extension.
The "this code can't fail" thing is the biggest challenge. It basically introduces a result of an operation which doesn't have to be a value, but can be a type, so prefix.foo<prefix.Bar>.new() is not an error because prefix.foo is "this unspecified thing".