Reputation: 7000
In implementing the Python module mechanism on top of ES6 modules for the Transcrypt Python to JavaScript compiler, I am faced with the following problem:
There are a large number of standard functions imported from the Python runtime module, like e.g. the Python input
function (implemented in JS), which can be made available using named imports (since they shouldn't have to be prefixed with anything in the user code, so input
rather than __runtime__.input
, to be consistent with Python).
In Python it's allowed to rebind named imports. So I define another function input
, which will override the one from the runtime. But if I do so in JS, I get an error:
Identifier 'input' has already been declared
It seems that all imported names are regarded as JS consts, so non-rebindable according to this article. I can think of several clever workarounds, like importing under an alias and then assigning to a module global var rather than const, but like to keep things simple, so my question is:
Upvotes: 0
Views: 690
Reputation: 388153
As per the language specification, imported bindings are immutable bindings, so they cannot be changed. The identifiers are reserved as the module gets parsed because of how ES6 modules work: Unlike in Python, imports are not statements that are included as they are executed; instead, all a module’s imports are basically collected during the early compilation and then resolved before the module starts executing.
This makes ES6 modules kind of unsuitable as an implementation for Python’s import system.
As a general way, to avoid losing those names, you can simply give the imported bindings different names. For example an from foo import bar, baz
may be compiled to the following:
import { bar as _foo__bar, baz as _foo__baz } from 'foo';
let bar = _foo__bar;
let baz = _foo__baz;
That will only reserve some special names while keeping the bar
and baz
identifiers mutable.
Another way, which would probably also help you to solve possible import semantics differences would be to simply create a closure:
import { bar, baz } from 'foo';
(function (bar, baz) {
// …
})(bar, baz);
Or even add some other lookup mechanism in between.
Btw. Python’s import
is very similar to Node’s require
, so it might be worth looking into all those solutions that made Node’s module system work in the browser.
Upvotes: 2