`this` inside modules
Dominic, those are some of the my notes, which by no means cover all the discussion around this topic. @ericf will be posting the full detailed explanation of the stuff we covered.
This is definitely an area that we should continue discussing, especially
the API of the "module meta" object, and how to access it from within the
module body. I can tell that @wycats and @ericf are opposed to any magic
surrounding the module execution (a la nodejs). In the other hand,
System.currentModule
is probably a bad idea because you don't know which
loader was used to load the module (remember that you can use a custom
loader for that).
As for the "execution context", the gist mutated multiple times (the original question was about the specs, and the lack of clarity about the evaluation of the module), and we ended up looking into the details of how to access the module meta and loader. Again, this is by no means a doc to reference.
On Mon, Jun 9, 2014 at 6:25 AM, Domenic Denicola <domenic at domenicdenicola.com> wrote:
The current proposal would instead create a world where
this
is about methods most of the time, but is a magic ambient variable in some cases (sloppy scripts, modules).
This also creates an ever bigger need for an external opt-in flag for modules. E.g. making service workers use strict mode as suggested in slightlyoff/ServiceWorker#294 would no longer allow us to safely upgrade them to module syntax later on. Per www.w3.org/Bugs/Public/show_bug.cgi?id=25868 it is argued that "use modules" would be bad UX, but that seems to be exactly where this is heading, except the syntax is outside of JavaScript.
I completely agree and was, in fact, going to write my own email on this topic, because I strongly believe we should leave this
alone in modules.
Instead, let’s turn “module this” into a module-local special variable with a name such as module
, thisModule
, currentModule
, etc.
Axel, using
module
was the first proposal analyzed (3.1 from the gist). I do like it a lot, but other in the meeting opposed to any sort of "automagic" by wrapping the module execution into a function execution with themodule
argument (a la nodejs),
Overloading this
feels even more magic to me and is much less self-descriptive. Apart from the overloading problems (which are significant!), I don’t see that much of a difference between passing in a value for this
and setting up a – descriptively named – module-scoped variable.
and the fact that
this
is not really the module, it is an object that contains, among other things, a reference to another object with the live binding, a relative import, a relative get, etc.
Give it a different name, then. Call it moduleDescriptor
, moduleData
, etc.
On Mon Jun 09 2014 at 12:25:42 AM, Domenic Denicola < domenic at domenicdenicola.com> wrote:
If a magically in-scope binding is necessary to access module meta capabilities, giving it a name like
module
orSystem.currentModule
would be much better.
System.currentModule
requires magic. It would require the engine to know
where the call site was.
We also talked about adding a binding, like NodeJS does but David Herman argued that that is a non starter.
So, if we don't want to use this
or introduce a new binding name, or add
more magic, the only thing left seems to be new dedicated syntax. In ES4 we
this function
which is similar to what Axel Rauschmayer suggested.
What if instead of any sort of magic there was a special relative import a person could specify to get access to the this module?
import module from "@currentModule";
I agree with Alex completely. Using this
as a module meta object is a
bad idea. Boo.
I guess it just seems odd to me that we HAVE a system in place now for
importing "stuff" into a Program with an author defined local identifier
name and we're discussing magic like using this or module. Just make it
another thing the author imports inside their own module? import meta from "./@meta";
or something in the ballpark. Let's use the system
we're creating to our advantage.
(Sorry for the "boo", but I can't mask my disappointment here.)
Erik, was was Dave's argument that a new binding is a non-starter?
That's true, but I don't understand why we can't just have (to use your example):
import module from "./@meta";
As an implicit import within each module.
Because that assumes everyone needs it all the time. The nice thing about it being opt-in is that when it comes time to use it a person has to first learn the entry point and from then on be explicit about it. I prefer explicitness 99% of the time because it's easier to track down for new contributors to a code base etc.
Also, if module were a reserved word and not already used by node.js as an identifier I MIGHT feel differently.
Because that assumes everyone needs it all the time. The nice thing about it being opt-in is that when it comes time to use it a person has to first learn the entry point and from then on be explicit about it. I prefer explicitness 99% of the time because it's easier to track down for new contributors to a code base etc.
Point taken, and you might be right. But Erik said that Dave said (!) that a binding was a non-starter, and I just don't see that yet.
Also, Yehuda Katz argued that module
is a common variable name (QUnit uses it) and reserving it is a non starter.
import {thisModule as yourName} from '@moduleMeta'
(bike shedding TBD) is
a promising path forward.
That makes sense - thanks!
Just another related issue: in Traceur code we use 'this' in modules to mean 'global', because in modules we have no other way to say 'global' in code designed to work in browsers and node.
Right - I do the same. I think leaving "this" to mean global would be just fine: there's no obvious advantage to changing this aspect of the design, this late in the game. And if there's no obvious advantage, then we're just churning.
The genuine global is typically the source of tremendous amounts of authority. Much of the mechanism of SES is built to deny access to the genuine global and to non-whitelisted global variables. Can the module loader API be used to load a module with a different top level binding for "this"?
IIUC, that use case is provided for with custom module loaders (where you can specify the realm and such).
another issue with this
being global
(as it is today by the specs) is
the way top level modules will be defined in a page, assuming we will have
type="module"
for scripts (which is probably were we want to be), what
will be the difference between:
<script type="module">
this.foo = 1;
var bar = 2;
import main from "main";
</script>
and
<script>
this.foo = 1;
var bar = 2;
System.import("main");
</script>
it seems to me that the current definition, where this
is global
, will
be an issue when it comes to avoid global variable definition. Ideally, for
modules, this.foo
and bar
will be contained, to have a clear
differentiation with the regular script
tags.
On Mon, Jun 9, 2014 at 9:40 AM, Caridy Patino <caridy at gmail.com> wrote:
another issue with
this
beingglobal
(as it is today by the specs) is the way top level modules will be defined in a page, assuming we will havetype="module"
for scripts (which is probably were we want to be), what will be the difference between:<script type="module"> this.foo = 1; var bar = 2; import main from "main"; </script>
and
<script> this.foo = 1; var bar = 2; System.import("main"); </script>
In the 'module', 'bar' is local and 'main' is imported before the module is evaluated. In 'script' bar is global and the 'main' is imported at the end of the script. The fate of 'this.foo' hangs in the balance until TC39 speaks.
it seems to me that the current definition, where
this
isglobal
, will be an issue when it comes to avoid global variable definition. Ideally, for modules,this.foo
andbar
will be contained, to have a clear differentiation with the regularscript
tags.
My point: if 'this' is not global in modules, then ES6 must have an alternative way to name the global object.
FWIW, I like the nodejs approach where this
is the module itself which as
"virtual sandbox" is the only this
I'd expect. To reach the global maybe
we should think about adding a global
indeed while having this
undefined would be just making modules not so reusable or portable and
would make this
meaningless ... which is kinda lame being the most
important feature of JS since kinda ever, IMO
My point: if 'this' is not global in modules, then ES6 must have an alternative way to name the global object.
Yes, we covered that last week. Reflect.global
seems like the right place
for it considering that it will be defined per realm.
What is an arrow function bound to in a module?
export var a = () => this;
What is an arrow function bound to in a module?
export var a = () => this;
As with all arrow functions, this
is lexically bound, so it will bind to
whatever this
is bound to within the module. Which is kinda the question
at hand.
once again, in node.js this
is the exported module. I think we should not
make it undefined
neither a global
pointer ... in node.js this
in
modules is never global except when you launch the console so only in the
main, where we are already consistently good on browsers since this
is
the global there (script on a page, not modules)
Do we really want to break interoperability with node.js when it comes to
this
inside modules which is a keyword that could not even be reassigned
to nothing and/or monkey patched ?
As tweeted earlier today: I can already smell the next stinking module
feature detection if (this) console.log("you are in nodejs") else alert("WTF browser module")
Best
Was this decision reversed? I don't see Reflect.global in the new spec. online. jjb
From my interpretation of the last face to face notes and the breakout
session it would appear as if instead you will be able to import mod from this
- Matthew Robb
I'm sorry I must have been thinking about something else. This is what I pulled from the last notes:
AWB:
import filename from this; // which basically: import filename from here;
DD: Like this for relative DH: Completely amenable to this YK:
import * as me from here; me.import; // `me` is the context object
Conclusion/Resolution
- the api is right direction
- each module gets its own version of that object
- need some sort of access to the module contextual object
- some sort of declarative form to get at
- static contextual information about the module
- Matthew Robb
The latest info from Domenic is:
import { name, url } from this module;
Source: esdiscuss.org/topic/es6
gist.github.com/caridy/eefb9b104874465d4e1c#2-whats-the-execution-context-for-a-module seems to indicate
this
will become some sort of module meta object with a variety of abilities:this.name
,this.address
,this.import
,this.get
, andthis.module
.This seems like another unfortunate addition to the WTFJS canon, as it continues to add more confusing meanings for
this
to the mix.IMO it would be much better to leave
this
asundefined
, just as it is in strict mode scripts, and thus be able to tell a consistent story that in ES6,this
is about methods. The current proposal would instead create a world wherethis
is about methods most of the time, but is a magic ambient variable in some cases (sloppy scripts, modules). This kind of confusion is evident even in the title of that section: it asks "what is the execution context for a module," but it is actually talking aboutthis
, which has nothing to do with execution contexts.If a magically in-scope binding is necessary to access module meta capabilities, giving it a name like
module
orSystem.currentModule
would be much better.