How to modify the scope chain without `with` ?

Coroutines coroutines at
Tue Feb 16 17:58:17 UTC 2016

On Tue, Feb 16, 2016 at 9:38 AM, Garrett Smith <dhtmlkitchen at> wrote:
> On Mon, Feb 15, 2016 at 1:13 AM, Coroutines <coroutines at> 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
>>               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
                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:
`function runWithinTagger(f) { with (env) { f(); } }`

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

runWithinTagger f

console.log html

More information about the es-discuss mailing list