Jacques de Hooge
Jacques de Hooge

Reputation: 7000

ES6 named import introduces a const?

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

Answers (1)

poke
poke

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

Related Questions