How to modify the scope chain without `with` ?

# Coroutines (9 years ago)

This post might be overly wordy. Sorry. It relates to the functionality provided by the with keyword and why I think it's important in the future.

I am currently rewriting a templating module that I think is very useful for it's ability to turn a function in coffeescript syntax into a sort of DSL - something that looks like this:

template = -> doctype 5 html -> head -> title @title body -> div id: 'content', -> if @posts? for p in @posts div class: 'post', -> p p.name div p.comment form method: 'post', -> ul -> li -> input name: 'name' li -> textarea name: 'comment' li -> input type: 'submit'

For those not familiar with Coffeescript, "= ->" creates a function

with no arguments, the indented sub-block is the body of the function.

All of these things essentially compile into nested functions like: html(head(title(this.title))

(not an exact translation)

Anyway, this library/module called (ck) exploits the little-used with keyword. It creates a function like this:

function (scope, template) { with (scope) { template(); } }

So the template is just a series of functions that lookup within scope for a function creating HTML. The problem is this module (imo) wastefully creates a lot of closures to create the HTML tags.

It was my plan to create a Proxy object to use like: with (proxy) { ... } - so html() called within that with block would redirect through the proxy to something like: makeTag('html', children...)

This does not work. Proxies as objects provided to with does not work. I don't know if this is intended but I'm disappointed. with itself is a keyword discouraged from use (it seems).

I am from Lua, where in Lua we have 2 variables called _ENV and _G. In Javascript terms _G would point to global in node (the main execution context/object). _ENV has no direct mapping to JS - it would be the current context/object, which might not be _G anymore.

I wish it were possible to create objects that functions could run within - you can seemingly only do this with the outmoded with or with the 'vm' module in Node. People seem to discourage with and it (iirc) is ignored in strict mode - and you can't use the vm module in the browser.

I think there is a need for the ability to do this in ES7, and I wish it were as simple as assigning an object to _ENV to change the environment the function dereferences/resolves through.

Am I crazy or is this a good idea? The MDN posting on the with keyword says you should just create a short reference to make use of things - like: ck.p("this is a paragraph"); - but then this isn't as natural as exploiting the context of what the function is running in for the above template function. Again - I am NOT talking about how this is defined but the outer scope/object. I wish scope lookup were as simple as following a prototype chain. I wish I could easily create a scope to run in from an object.

Would this be something useful - or is with just not in style anymore? (I'm still mad I can't use a Proxy in with):

require('harmony-reflect');

let f = function() { cats('abc'); dogs('123'); thisshouldjustlog('damnit'); };

let tmp = new Proxy({}, { get: function() { return console.log; } });

// disappointment abound with (tmp) { f() };

# Andreas Rossberg (9 years ago)

On 15 February 2016 at 10:13, Coroutines <coroutines at gmail.com> wrote:

This post might be overly wordy. Sorry. It relates to the functionality provided by the with keyword and why I think it's important in the future.

I am currently rewriting a templating module that I think is very useful for it's ability to turn a function in coffeescript syntax into a sort of DSL - something that looks like this:

template = -> doctype 5 html -> head -> title @title body -> div id: 'content', -> if @posts? for p in @posts div class: 'post', -> p p.name div p.comment form method: 'post', -> ul -> li -> input name: 'name' li -> textarea name: 'comment' li -> input type: 'submit'

For those not familiar with Coffeescript, "= ->" creates a function with no arguments, the indented sub-block is the body of the function.

All of these things essentially compile into nested functions like: html(head(title(this.title))

(not an exact translation)

Anyway, this library/module called (ck) exploits the little-used with keyword. It creates a function like this:

function (scope, template) { with (scope) { template(); } }

So the template is just a series of functions that lookup within scope for a function creating HTML. The problem is this module (imo) wastefully creates a lot of closures to create the HTML tags.

It was my plan to create a Proxy object to use like: with (proxy) { ... } - so html() called within that with block would redirect through the proxy to something like: makeTag('html', children...)

This does not work. Proxies as objects provided to with does not work. I don't know if this is intended but I'm disappointed. with itself is a keyword discouraged from use (it seems).

I am from Lua, where in Lua we have 2 variables called _ENV and _G. In Javascript terms _G would point to global in node (the main execution context/object). _ENV has no direct mapping to JS - it would be the current context/object, which might not be _G anymore.

I wish it were possible to create objects that functions could run within - you can seemingly only do this with the outmoded with or with the 'vm' module in Node. People seem to discourage with and it (iirc) is ignored in strict mode - and you can't use the vm module in the browser.

I think there is a need for the ability to do this in ES7, and I wish it were as simple as assigning an object to _ENV to change the environment the function dereferences/resolves through.

Am I crazy or is this a good idea? The MDN posting on the with keyword says you should just create a short reference to make use of things - like: ck.p("this is a paragraph"); - but then this isn't as natural as exploiting the context of what the function is running in for the above template function. Again - I am NOT talking about how this is defined but the outer scope/object. I wish scope lookup were as simple as following a prototype chain. I wish I could easily create a scope to run in from an object.

Would this be something useful - or is with just not in style anymore? (I'm still mad I can't use a Proxy in with):

require('harmony-reflect');

let f = function() { cats('abc'); dogs('123'); thisshouldjustlog('damnit'); };

let tmp = new Proxy({}, { get: function() { return console.log; } });

// disappointment abound with (tmp) { f() };

Without wanting to say much on the overall viability of your plan, but proxies do work with with. However, your code has at least two bugs:

(1) It's not defining a custom has trap. That is needed for with, otherwise it will just check the target object, which has no f.

(2) You cannot return console.log first-class and expect it to work (at least not on all browsers). Known JavaScript issue.

This fixed version works fine on V8 4.9 / Chrome 49:

function f() { console.log("failure") }

let p = new Proxy({}, { has() { return true }, get() { return x => console.log(x) } });

with (p) { f("success") };

# Benjamin Gruenbaum (9 years ago)

For what it's worth very popular templating libraries like KnockoutJS use woth heavily.

I think the consensus is that writing DSLs should be done as a transformation into JavaScript (like JSX) and not inside JavaScript (like Knockout and your library)

The dynamic nature of with is why it is forbidden in strict mode, when import/export land in browsers things will run in strict mode by default which means with is gone.

# Bradley Meck (9 years ago)

This npm module might help you out. www.npmjs.com/package/with

It is used by several engines for similar effects without the strain on the VM "with" causes.

# Coroutines (9 years ago)

On Mon, Feb 15, 2016 at 4:48 AM, Benjamin Gruenbaum <inglor at gmail.com> wrote:

For what it's worth very popular templating libraries like KnockoutJS use woth heavily.

I think the consensus is that writing DSLs should be done as a transformation into JavaScript (like JSX) and not inside JavaScript (like Knockout and your library)

The dynamic nature of with is why it is forbidden in strict mode, when import/export land in browsers things will run in strict mode by default which means with is gone.

Aside from this, I wish JS would provide the ability to modify the scope chain - and it should be just objects that can inherit from one another through prototypes. I think it would be too perfect/clean to handle scope in the existing way we handle inheritance. My example isn't completely justified to say "I need this" - but I think having direct control over scope would be important in the future and should be considered for ES7. Especially if the existing way is not portable anymore...

I don't think it would be a security concern either, as you could only make objects you have reference to your new scope.

# Coroutines (9 years ago)

On Mon, Feb 15, 2016 at 1:43 AM, Andreas Rossberg <rossberg at google.com> wrote:

Without wanting to say much on the overall viability of your plan, but proxies do work with with. However, your code has at least two bugs:

(1) It's not defining a custom has trap. That is needed for with, otherwise it will just check the target object, which has no f.

(2) You cannot return console.log first-class and expect it to work (at least not on all browsers). Known JavaScript issue.

This fixed version works fine on V8 4.9 / Chrome 49:

function f() { console.log("failure") }

let p = new Proxy({}, { has() { return true }, get() { return x => console.log(x) } });

with (p) { f("success") };

/Andreas

Thank you very, very much! I feel embarrassed I missed that it needed a has(), but I am glad I have a solution that works now - I thought it impossible!

# Andreas Rossberg (9 years ago)

On 15 February 2016 at 18:49, Coroutines <coroutines at gmail.com> wrote:

On Mon, Feb 15, 2016 at 4:48 AM, Benjamin Gruenbaum <inglor at gmail.com> wrote:

For what it's worth very popular templating libraries like KnockoutJS use woth heavily.

I think the consensus is that writing DSLs should be done as a transformation into JavaScript (like JSX) and not inside JavaScript (like Knockout and your library)

The dynamic nature of with is why it is forbidden in strict mode, when import/export land in browsers things will run in strict mode by default which means with is gone.

Aside from this, I wish JS would provide the ability to modify the scope chain - and it should be just objects that can inherit from one another through prototypes. I think it would be too perfect/clean to handle scope in the existing way we handle inheritance. My example isn't completely justified to say "I need this" - but I think having direct control over scope would be important in the future and should be considered for ES7. Especially if the existing way is not portable anymore...

That would be a total and complete disaster for implementations, as it would make scopes observable and mutable in a way that absolutely breaks all conventional compilation and optimisation techniques for local variables, closures, etc. JavaScript would easily become 10-100x slower. Like when you use with today.

I don't think it would be a security concern either, as you could only

make objects you have reference to your new scope.

It would totally break security as well, given that functions could then peek into local variables on their call chain through proto. And I cannot even fathom what it would mean to mutable some proto!

# Coroutines (9 years ago)

On Mon, Feb 15, 2016 at 11:51 PM, Andreas Rossberg <rossberg at google.com> wrote:

That would be a total and complete disaster for implementations, as it would make scopes observable and mutable in a way that absolutely breaks all conventional compilation and optimisation techniques for local variables, closures, etc. JavaScript would easily become 10-100x slower. Like when you use with today.

It was not my plan to move closed-over values and local variables into an Object as part of a chain of prototyped, inherited objects. I only wanted to make it possible to set the "global" environment, and have that object follow prototypical inheritance.

To this I would ask - which specific optimisations would it compromise?

It would totally break security as well, given that functions could then peek into local variables on their call chain through proto. And I cannot even fathom what it would mean to mutable some proto!

In what I envisioned, it would not expose local or closed-over variables - they would not be part of the environment Object I'm talking about.

My inspiration is that you could prepare sandbox environments that you construct and derive from cleanly - without using something like the vm module only found in Node. Currently if you want to "sandbox" the environment in the browser you have to lose references to things you consider dangerous (of course) - but that is "forever". You cannot leave any reference to anything unsafe and once it's done it's done. Having the ability to derive from "global" (only in Node) and prepare an Object to run an function within as its global context would be an invaluable ability. (imo)

# Michał Wadas (9 years ago)

2016-02-16 15:51 GMT+01:00 Coroutines <coroutines at gmail.com>:

Having the ability to derive from "global" (only in Node) and prepare an Object to run an function within as its global context would be an invaluable ability. (imo)

It seems like an obvious idea, but in fact it's almost impossible to secure

  • consider true.constructor.constructor("alert('XSS')")() ECMAScript lacks secure sandbox that would work in every browser, but such limited scope manipulation is totally useless as "secure sandbox".

BTW, such limited scope manipulation is already possible, see how my library works there - Ginden/reflect-helpers/blob/master/tests/closures.js#L14 (it heavily uses eval).

Sending again because of wrong "to".

# Coroutines (9 years ago)

On Tue, Feb 16, 2016 at 7:45 AM, Michał Wadas <michalwadas at gmail.com> wrote:

2016-02-16 15:51 GMT+01:00 Coroutines <coroutines at gmail.com>:

Having the ability to derive from "global" (only in Node) and prepare an Object to run an function within as its global context would be an invaluable ability. (imo)

It seems like an obvious idea, but in fact it's almost impossible to secure

  • consider true.constructor.constructor("alert('XSS')")() ECMAScript lacks secure sandbox that would work in every browser, but such limited scope manipulation is totally useless as "secure sandbox".

BTW, such limited scope manipulation is already possible, see how my library works there - Ginden/reflect-helpers/blob/master/tests/closures.js#L14 (it heavily uses eval).

Sending again because of wrong "to".

Okay - different argument: if you can provide actual environment inheritance you can avoid collisions assigning to the "global scope".

# /#!/JoePea (9 years ago)

But then, you might as well start using modules and properly scoping variables, as that will lend to much more readable code.

(Sent again, wrong "from")

/#!/JoePea

# /#!/JoePea (9 years ago)

Seems like changing the global could lead to problems where a developer might assumes certain globals but hey different ones, which imho could make the use of globals even messier. I imagine you would like Angular's $scope inheritance, which is sort of like what you want ( angular/angular.js/wiki/Understanding-Scopes).

/#!/JoePea

# /#!/JoePea (9 years ago)

/#!/JoePea On Feb 16, 2016 9:13 AM, "/#!/JoePea" <joe at trusktr.io> wrote:

Seems like changing the global could lead to problems where a developer

might assumes certain globals but hey

I meant: "but have" different ones. Importing things explicitly into modules (instead of (inherited) globals) helps better understand the requirements of a given piece of code imo.

different ones, which imho could make the use of globals even messier. I

imagine you would like Angular's $scope inheritance, which is sort of like what you want ( angular/angular.js/wiki/Understanding-Scopes).

/#!/JoePea

On Feb 16, 2016 9:10 AM, "/#!/JoePea" <joe at trusktr.io> wrote:

But then, you might as well start using modules and properly scoping

variables, as that will lend to much more readable code.

(Sent again, wrong "from")

/#!/JoePea

On Feb 16, 2016 7:57 AM, "Coroutines" <coroutines at gmail.com> wrote:

On Tue, Feb 16, 2016 at 7:45 AM, Michał Wadas <michalwadas at gmail.com>

wrote:

2016-02-16 15:51 GMT+01:00 Coroutines <coroutines at gmail.com>:

Having the ability to derive from "global" (only in Node) and prepare an Object to run an function within as its global context would be an invaluable ability. (imo)

It seems like an obvious idea, but in fact it's almost impossible to

secure

  • consider true.constructor.constructor("alert('XSS')")() ECMAScript lacks secure sandbox that would work in every browser, but

such

limited scope manipulation is totally useless as "secure sandbox".

BTW, such limited scope manipulation is already possible, see how my

library

works there -

Ginden/reflect-helpers/blob/master/tests/closures.js#L14

# Coroutines (9 years ago)

On Tue, Feb 16, 2016 at 9:16 AM, /#!/JoePea <joe at trusktr.io> wrote:

/#!/JoePea On Feb 16, 2016 9:13 AM, "/#!/JoePea" <joe at trusktr.io> wrote:

Seems like changing the global could lead to problems where a developer might assumes certain globals but hey

I meant: "but have" different ones. Importing things explicitly into modules (instead of (inherited) globals) helps better understand the requirements of a given piece of code imo.

different ones, which imho could make the use of globals even messier. I imagine you would like Angular's $scope inheritance, which is sort of like what you want (angular/angular.js/wiki/Understanding-Scopes).

I was just thinking about the import we gained in ES6. In Perl and Python you might have functions imported directly into the global scope (of the current context) - so that it's easier to just write the function name without the short reference you imported it in as:

cos(PI) vs Math.cos(Math.PI) etc...

I was simply thinking it could give you the ability to choose how you prefer to write that. If you're not using several modules and the code you're writing is quite focused in one area it might look cleaner (less redundant) to import Math and have all its functions be accessible as "globals". If you are writing code that ties together functions from Math, fs, and tls modules (for some reason??) it would make sense to do the existing:

var fs = require('fs'); var tls = require('tls'); ...

Anyway, if we had control over the global scope/context/Object, it would allow you to make these design decisions in an effort to write code that I would sometimes view as cleaner. What I think is important is that you could have your existing scope inherit from the "first" global scope, but when you assign to the current global scope it is set there. Your modifications don't extend globally to the rest of the project. Also if you want to isolate your current scope from the global scope you don't have to have one inherit from the other - you can break it's prototype (or never form it). Again, as the other guy pointed out - it's not a complete or even marginally safe "sandbox" but all in all I think it's something we should have control over if we want to simplfy how modules are created (for one) without polluting the existing global scope/Object.

My responses are a bit wordy/disorganized...

# Garrett Smith (9 years ago)

On Mon, Feb 15, 2016 at 1:13 AM, Coroutines <coroutines at gmail.com> wrote:

This post might be overly wordy. Sorry. It relates to the functionality provided by the with keyword and why I think it's important in the future.

I am currently rewriting a templating module that I think is very useful for it's ability to turn a function in coffeescript syntax into a sort of DSL - something that looks like this:

template = -> doctype 5 html -> head -> title @title body -> div id: 'content', -> if @posts? for p in @posts div class: 'post', -> p p.name div p.comment form method: 'post', -> ul -> li -> input name: 'name' li -> textarea name: 'comment' li -> input type: 'submit'

For those not familiar with Coffeescript, "= ->" creates a function with no arguments, the indented sub-block is the body of the function.

All of these things essentially compile into nested functions like: html(head(title(this.title))

(not an exact translation)

Anyway, this library/module called (ck) exploits the little-used with keyword. It creates a function like this:

function (scope, template) { with (scope) { template(); } }

So the template is just a series of functions that lookup within scope for a function creating HTML. The problem is this module (imo) wastefully creates a lot of closures to create the HTML tags.

I think you'll have a lot better luck starting out like I did: Learn HTML first. You're working on some complicated stuff there, and for me, I always try to get simple to work. Simple and working is good!

You cannot have too solid of a grasp of HTML. Ditto for CSS.

When it comes to javascript, context and scope can be tricky and confusing for those coming from other languages.

Thank you,

# /#!/JoePea (9 years ago)

/#!/JoePea On Feb 16, 2016 9:38 AM, "Coroutines" <coroutines at gmail.com> wrote:

On Tue, Feb 16, 2016 at 9:16 AM, /#!/JoePea <joe at trusktr.io> wrote:

/#!/JoePea On Feb 16, 2016 9:13 AM, "/#!/JoePea" <joe at trusktr.io> wrote:

Seems like changing the global could lead to problems where a developer might assumes certain globals but hey

I meant: "but have" different ones. Importing things explicitly into

modules

(instead of (inherited) globals) helps better understand the

requirements of

a given piece of code imo.

different ones, which imho could make the use of globals even messier.

I

imagine you would like Angular's $scope inheritance, which is sort of

like

what you want (angular/angular.js/wiki/Understanding-Scopes).

I was just thinking about the import we gained in ES6. In Perl and Python you might have functions imported directly into the global scope (of the current context) - so that it's easier to just write the function name without the short reference you imported it in as:

cos(PI) vs Math.cos(Math.PI) etc...

You could

let {cos, PI} = Math

console.log(cos(PI))
# Coroutines (9 years ago)

On Tue, Feb 16, 2016 at 9:38 AM, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

On Mon, Feb 15, 2016 at 1:13 AM, Coroutines <coroutines at gmail.com> wrote:

This post might be overly wordy. Sorry. It relates to the functionality provided by the with keyword and why I think it's important in the future.

I am currently rewriting a templating module that I think is very useful for it's ability to turn a function in coffeescript syntax into a sort of DSL - something that looks like this:

template = -> doctype 5 html -> head -> title @title body -> div id: 'content', -> if @posts? for p in @posts div class: 'post', -> p p.name div p.comment form method: 'post', -> ul -> li -> input name: 'name' li -> textarea name: 'comment' li -> input type: 'submit'

For those not familiar with Coffeescript, "= ->" creates a function with no arguments, the indented sub-block is the body of the function.

All of these things essentially compile into nested functions like: html(head(title(this.title))

(not an exact translation)

Anyway, this library/module called (ck) exploits the little-used with keyword. It creates a function like this:

function (scope, template) { with (scope) { template(); } }

So the template is just a series of functions that lookup within scope for a function creating HTML. The problem is this module (imo) wastefully creates a lot of closures to create the HTML tags.

I think you'll have a lot better luck starting out like I did: Learn HTML first. You're working on some complicated stuff there, and for me, I always try to get simple to work. Simple and working is good!

You cannot have too solid of a grasp of HTML. Ditto for CSS.

When it comes to javascript, context and scope can be tricky and confusing for those coming from other languages.

Thank you,

With respect - for this particular project I wanted to gut it to be as small as possible. What fascinates me about this module (ck) is how it abuses lookups in the scope chain to form HTML - while similarly looking great as valid Coffeescript. It has been my aim to remove as many responsibilities from it to instead put on the user or on other libraries. I do not want this module to worry about if <lol> is a

valid HTML tag - just that the tag itself is well-formed (disregarding self-closing tags). I have already removed auto-indenting the resulting HTML as that can be done with js-beautify in another part of the overall pipeline (a gulp task for instance).

The frustration I'm having is that with is no longer in style. I can get it to work with a Proxy (as Andreas corrected for me) - but it still requires I keep a list of valid HTML tags - so the has() handler in the proxy will work correctly. The problem is the scope lookup I need is in the wrong order - I wanted it to look at the existing scope and if a function doesn't exist, then resolve it through the Proxy so it creates the closure which creates the HTML tag. Currently this is reversed - which is why I have to keep the list of HTML tags. If I could reverse it I could remove more code.

I don't have the needed control over scope I want - I can't resolve through the existing scope and fallback on a Proxy to generate a function/closure as needed. That is my problem with scope.

Anyway, I understand if this is not the right place to talk about my specific project problem - but I thought it would be important to start a discussion about scope. I'm lobbying to have this control someday. Again, with WebAssembly in the future to support the scoping rules of other languages that will compile to the WebAssembly AST it will have to be loosely based on what Javascript supports.

Here's the non-working version of what I had in mind (forgive the coffeescript) - but it somewhat illustrates what I'm talking about with "with + Proxy" (dynamic?) scoping:

require('assert').ok Proxy?, 'no Proxy!!' require 'harmony-reflect'

html = ''

isString = (x) -> typeof x is 'string' or x instanceof String

env = new Proxy {}, # this is a problem - I can't make use of existing functions # "behind" the Proxy if I always return true (from the existing, non-with scope) has: -> true get: (_, prop) -> (attrs, body) -> makeTag prop, attrs, body

makeTag = (tag, attrs, body) -> unless typeof attrs is 'object' body = attrs attrs = {}

    attrs = ("#{attr}=\"#{value}\"" for own attr, value of attrs

when value? and value isnt false).join ' '

    # intended coercion here
    if attrs
            attrs = " #{attrs}"

    html += "<#{tag}#{attrs}>"

    # if there is no body, this is a self-closing tag (the user

knows HTML not us) return unless body?

    if isString
            html += body
    else
            runWithinTagger body

    html += "</#{tag}>"

f() creates an <f> - this is flawed. in the ck module a Function is

created from the edited toString() of f:

blitmap/ck/blob/master/lib/ck.coffee#L82-L84

function runWithinTagger(f) { with (env) { f(); } }

f = -> h1 'Hello', 'this header here' p 'this is a paragraph'

runWithinTagger f

console.log html

# Coroutines (9 years ago)

On Tue, Feb 16, 2016 at 9:57 AM, /#!/JoePea <joe at trusktr.io> wrote:

You could

let {cos, PI} = Math

console.log(cos(PI))

Oh I agree there - if you're only using a few functions from a module it makes sense to create local references to them. I just thought something like this would be nice if you are drawing upon 20+ functions from Math and you don't want to write "Math." everywhere. Even "m.".

tmp = Object.assign({}, Math);
tmp = Object.setPrototypeOf(tmp, _ENV);
_ENV = tmp; # "global" scope chain would be: Math -> previous module

scope object

exports.someFunction = (x) => cos(PI);
...
...
...
# Coroutines (9 years ago)

To me "don't use with - assign the object to a smaller reference" just seems unsustainable.

Say you're using a bunch of functions from 'ReallyLongModuleName'.

So you do something like this:

var x = require('ReallyLongModuleName');

And you start doing this everywhere:

x.something(); x.thatThingOverThere(); console.log(x.Whatever() + x.thisIsAnnoying());

It just becomes a chore to write "x." everywhere - which is what makes with (x) { ... } so attractive.

Again, this is predicated on you wanting to use say 15+ functions from a module that has a really long name. And that's assuming it's the only module with a really long name. Some people (me) have trouble coming up with short, meaningful names for things which ordinarily would have long names. So these people (me) would use common short identifiers - like: var $ = require(...);

Well shit, now we're confusing people further. var x, y, z, $ = require('this has to end somewhere');

Global scope should be something you can replace and prototype. Maybe not for security - not a sandbox - but for managing how concisely one can refer to the functions they need to. (Again: For instances where you're using many functions from a module and it makes sense to just populate the object acting as the global scope with them).

We should be able to manage global/window better, and I think this has merit for ES7.

PS: with only allows you to put an object at the front of the scope chain, what I'm suggesting would allow you to fallback on another scope with inheritance.

PPS: Some modules overwrite the identifiers they use in the global scope, even when they assign into module.exports (which is naughty). Being able to portably construct the global scope object a function runs in can prevent this messiness. We need Node's nodejs.org/api/vm.html#vm_vm_runincontext_code_contextifiedsandbox_options

Personally I'd prefer a special keyword:

_ENV = {}; // empty global scope, no Array, no String, but still reachable through [].prototype of course.

# Isiah Meadows (9 years ago)

FYI, this part might not work as you might expect. I've already been tripped up by similar.

var o = {
  index: 0,
  func() { return this.index++ },
}

with (o) {
  func() // TypeError: Cannot read property 'index' of undefined
}

The other reasons with is deprecated are because dynamic scoping is extremely hard to optimize and it's no longer obvious what variables are defined in that block (static analysis no longer works).

As for the global scope, I'll refer you to the System.global proposal: tc39/proposal-global Isiah Meadows me at isiahmeadows.com

# Coroutines (9 years ago)

On Mon, Feb 22, 2016 at 4:07 AM, Isiah Meadows <isiahmeadows at gmail.com> wrote:

FYI, this part might not work as you might expect. I've already been tripped up by similar.

var o = {
  index: 0,
  func() { return this.index++ },
}

with (o) {
  func() // TypeError: Cannot read property 'index' of undefined
}

To me this is expected... I am accustomed to 'use strict'.

The other reasons with is deprecated are because dynamic scoping is extremely hard to optimize and it's no longer obvious what variables are defined in that block (static analysis no longer works).

All I'm proposing is that we be given the ability to replace the global scope/Object by assigning to a special reference (_ENV = {}) - which would be scoped to the block, not forever-changed throughout the entire project/runtime. It shouldn't change the layout of how the global scope is referenced on the stack in any implementation (v8? Chakra?). And then of course that global scope object could be prototyped like any other object to provide inheritance/additional scoping.

I am used to having this control in Lua - it works really nicely there. I hate to be "that guy" but I've seen this used to help people manage and keep their code readable. It's all just managing namespaces. If I'm writing a module that defines a lot of Math functions I want the scope I define these functions in to be imbued with the existing facilities from Math. I want to directly invoke cos() not Math.cos(). From the point of view of my math-related code I don't want to have the main, global perspective of the script that is loading my module. I might make use of other modules that do not have a Math focus, and for that I will associate identifiers that go with their function: let log = require('logging');

To me this makes perfect sense, but the only way to do this (assuming we never use with again) is for every module to be referenced through a local, possibly shortened identifier and not touch the global scope at all. Repeating identifiers over and over is not concision, it's not DRY - it's tedium. I cannot be as expressive as I want, nor can I make use of the environment I need - and mess it up (temporarily). On that 2nd note, I wish module loading were as simple as this to prevent global destruction:

Loading a module should be:

  1. Resolve to the path of the module (or <script> href?)

  2. Fetch/read the file/script

  3. Construct a global env/object that inherits from the existing environment

  4. Run the script as a function/block within this new environment

  5. Cache the exports value.

  6. Return this value to the caller

I think Node does this essentially (which is why we have a global reference to the "real" environment), but "normal" JS does not. We hide what we can in closures, but code that does not export in the many fabulous ways we've come up with can have a lasting effect on the global scope. I like that to explicitly mutilate the global scope (not module-scope) I have to type global[prop] = ....

Personal opinion: I prefer runtime analysis to static analysis. Not a huge fan of type annotations and "strong mode" trying to cement a type's ABI to eek out more performance. I mean yes, optimizations are great but I'd rather have flexiblity to express myself how I want over limitations that save me negligible amounts of time..

# Isiah Meadows (9 years ago)

Okay. Now I understand what you're wanting. That's something that I'd expect would be expensive, but I'm not fundamentally against it. I'm into performance as well (and not just "I'm into it because it sounds bad if I'm not"), but performance is a weird beast at times. I've found that occasionally, the more dynamic features also help tremendously. Also, strict typing is mostly useful if you're writing something at scale. I tend to lean to dynamic features in smaller things, and static style in larger libraries and applications. I see benefits to both.

Back to the original topic, I feel swapping the global is potentially dangerous, but you should hopefully know what you're doing if you do.