es-discuss Digest, Vol 67, Issue 40

Joe Spencer js.developer.undefined at gmail.com
Fri Sep 14 14:11:04 PDT 2012


Sent from my Cricket smartphone

es-discuss-request at mozilla.org wrote:

>Send es-discuss mailing list submissions to
>	es-discuss at mozilla.org
>
>To subscribe or unsubscribe via the World Wide Web, visit
>	https://mail.mozilla.org/listinfo/es-discuss
>or, via email, send a message with subject or body 'help' to
>	es-discuss-request at mozilla.org
>
>You can reach the person managing the list at
>	es-discuss-owner at mozilla.org
>
>When replying, please edit your Subject line so it is more specific
>than "Re: Contents of es-discuss digest..."
>
>Today's Topics:
>
>   1. Re: Generator issue: exceptions while initializing arguments
>      (Dmitry Soshnikov)
>   2. Re: Generator issue: exceptions while initializing arguments
>      (Kevin Smith)
>   3. Re: Generator issue: exceptions while initializing arguments
>      (Jason Orendorff)
>   4. Re: Generator issue: exceptions while initializing arguments
>      (Kevin Smith)
>   5. Re: Some questions about Private Name Objects (Kevin Smith)
>
>On Wed, Sep 12, 2012 at 5:13 AM, Brendan Eich <brendan at mozilla.com> wrote:
>
>
>> You say it's too error prone but you don't adduce any evidence.
>>
>> Meanwhile we have lots of extant code that does things like
>>
>>   function foo(bar, baz) {
>>     baz = baz || default_baz;
>>     ...
>>   }
>>
>> That's the cowpath we are paving.
>>
>
>I see. Although, I cannot recall any other language which uses complex
>expressions (such as function calls, or even referencing to the neighbor
>parameters) for defaults. Usually they are just literals (no matter which,
>primitive or objects -- they are recreated every time at activation).
>
>But, I agree, they way you describe brings more power, and maybe JS will be
>the first language with such semantics for defaults.
>
>If so, then it's just the matter of the specification to notice all the
>subtle cases.
>
>function getDefaul() {}
>
>function foo(bar = [], baz = bar, quz = getDefault()) {
>  function getDefault() {}
>}
>
>The first thing which will confuse the devs is that `getDefault()`
>expression is not the immediate function call to only _initialize_ the
>default value of "quz", but is the syntactic form of calling this function
>every time to calculate the default value. This should be mentioned very
>explicitly, because from the top-down code viewing it really looks like
>getDefault() is just an initialize of the default, and in this view, its
>scope is even looks like the outer scope.
>
>Second, of course the scope of all the defaults expressions, with the bold
>font: "Notice, that the scope of defaults evaluation is the body of the
>function. This is done to support referencing to the neighbor arguments".
>
>As for generators,
>
>function createGen(foo = thrower()) {
>  yield 1;
>}
>
>var gen = createGen(); // loc1
>gen.next(); // loc2
>
>Of course the devs (again, w/o referencing to spec or detailed docs), would
>expect that the "thrower()" is called right away when the "createGen"
>function is defined. After they have read the docs, and now know that such
>function calls are executed at function activation instead, they would
>expect that the "thrower()" is called at "loc1", when the function is
>activated to create the generator object.
>
>OTOH, we understand the technical implementation, that the call to
>"createGen" may not execute the function body, and therefore, not to call
>"thrower()". And this is again will be too confusing for novices (?) that
>it (by the technical details/implementation?) should/may be an "loc2".
>
>So, if all these things described above are worth
>doing/supporting/explaining/etc., then we can build defaults based on "foo
>= foo || bar()" pattern which is used today. Then it's completely OK, I
>agree, it's powerful.
>
>However, if to take new programmers which will join JS from now,
>potentially they should not know about old patterns for defaults as "foo =
>foo || default", and they can use simple defaults as literals only.
>
>In some/many languages the defaults are used with `null`s only to be able
>to call a function with lesser parameters number. E.g. (PHP):
>
>function foo($foo, $bar = null) {
>  if (!$bar) {
>    $bar = $this->getDefault();
>  }
>}
>
>And now they can use foo(10), or foo(10, "bar"); But still, the expression
>which calculates the default $bar is described explicitly inside (in the
>scope of) the function.
>
>JS has no such problems, we may call foo(), or foo(10), or foo(10, "bar")
>regardless default values, even today.
>
>Also, the fact, that the expressions should be calculated at activation,
>not creation, comes from legacy, when function declarations should be
>created on entering the context. Then, even this code:
>
>var foo = function () {};
>
>function bar(baz = foo()) {
>  ...
>}
>
>Should not logically work, since "bar", being a FD, is created on entering
>the context, when "foo" is not function yet. This can satisfy the
>activation frame + activation time rules for such expressions.
>
>Dmitry
>
>>
>> We still have the choice of the implicit yield going after argument
>> defaulting, not before. SpiderMonkey implements before, though, and my own
>> argument from compositionality, above, makes it more clear to me that we
>> should go with implicit-yield-first. This makes contrived throwing
>> parameter default expressions throw "late" but if that matters, use a
>> function combined with a generator.
>>
>> In this thread, you and I have agreed on simpler scope/hoisting/defaulting/
>> **initialisting a la ES1-5. I think on reflection that this argues for
>> the implicit yield in a generator function going before anything with
>> observable effects, including argument defaulting.
>
>
>Sorry to backtrack the thread, but this is going to cause riots.
>
>    function* g(a, b = makeTheWorldABetterPlace()) { ... }
>
>    let iter = g(123);
>    // Is the world a better place yet?  I hope so.
>    iter.next();
>
>No amount of argument is going to convince a user that defaults should
>*not* be executed at the location of the call.  That's just not how it
>reads.  No?
>
>Kevin
>
>On Thu, Sep 13, 2012 at 8:23 PM, Kevin Smith <khs4473 at gmail.com> wrote:
>> No amount of argument is going to convince a user that defaults should *not*
>> be executed at the location of the call.  That's just not how it reads.  No?
>
>I kind of agree, but at this point we could do with a little less
>argument and a little more in the way of concrete proposals.
>
>So here is a concrete proposal. Please improve on it; it’s an honest
>attempt, not a straw man in the rhetorical sense...
>
>I think Allen is proposing a scheme where in code like
>
>    function f(a1=EXPR1, a2=EXPR2, a3=EXPR3) { ... }
>    f();
>
>first EXPR1 is evaluated in a scope including only a1,
>then EXPR2 is evaluated in a scope that contains a1 and a2,
>then EXPR3 is evaluated in a scope that contains a1, a2, and a3,
>then a new environment is created for the function body, its vars and
>local functions.
>
>If EXPR1 contains a closure that uses the name a2, that means the
>global a2, not the argument a2. Even if it gets called after a2 is
>bound.
>
>In the spec language this would have to be modeled with four nested
>environments; a single mutable environment wouldn't work. In
>SpiderMonkey, if any of the EXPRs contained a closure that uses with
>or direct eval, we would have to actually reify one of the nested
>environments. Ugly but doable; any other implementors want to comment?
>
>There would have to be some specification hackery to make this work
>just like ES3 in cases where f also contains a var or function with
>the same name as an argument. But Allen can do it. :)
>
>I don’t have a strong preference. It seems to be is a classic Right
>Thing vs. Worse Is Better situation. The advantage of the Worse Is
>Better approach is that you can correctly and completely explain
>what’s going on in one sentence: “It’s just like an if statement at
>the top of the function body.”  It may not be reasonable, but ordinary
>developers can reason about it. When it comes to corner cases, which
>is more important?
>
>-j
>
>
>>
>> I don’t have a strong preference. It seems to be is a classic Right
>> Thing vs. Worse Is Better situation. The advantage of the Worse Is
>> Better approach is that you can correctly and completely explain
>> what’s going on in one sentence: “It’s just like an if statement at
>> the top of the function body.”  It may not be reasonable, but ordinary
>> developers can reason about it. When it comes to corner cases, which
>> is more important?
>>
>
>Apologies for not making this clear earlier, but I agree with the "Worse is
>Better" approach.  That is, execute defaults in the scope of the function
>body.  When I tried to formulate the scope boundaries (as you have) it
>became clear to me that it would be convoluted any other way.
>
>What I'm questioning now is the idea that, in generators, the implicit
>first yield should occur *before the defaults are evaluated*.  I don't
>think that's a tenable position.  Is there an implementation problem with
>inserting the implicit first yield *after* the defaults are evaluated but
>*before* the rest of the function body?
>
>Thanks for your time on this, BTW.
>
>Kevin
>
>>
>> The real point I'm trying to make is that Name objects give us something
>> akin to clojure's protocols. Imagine an "orm" protocol -- this is just a
>> set of names that must exist on an object (or its proto chain). An object
>> can implement any number of protocols (or interfaces, or whatever) without
>> fear of conflict. You can easily override any implementation so long as you
>> have a handle on the appropriate name object. This is easier, better
>> looking and more correct than anything we can do today. It's not too
>> disimilar from using using instanceof as a brand, but without the pitfalls
>> (it doesn't fall flat crossing sandbox boundaries). This is a safe and
>> flexible inheritance model that works just as a js programmer would expect,
>> all without begging for mutable or multiple prototypes.
>>
>
>I think this is a winning argument.  So the problem becomes: how can we
>implement this in a non-fugly way?  As it stands (and as Allen has pointed
>out), we don't currently have the syntax to make this work, even for
>"iterator":
>
>    import iterator from "sys:iterator"; // Sorry, hate @'s : )
>
>    class Derived extends Base {
>
>      // Hmmm... No way to put iterator here.
>    }
>
>    // Try here?  Fugly...
>    X.prototype[iterator] = function() {
>
>      super.doSomething(); // Oops - super outside of class definition : (
>    };
>
>The absolute minimum we need is a way to specify computed property names in
>classes (and what the heck, object literals too):
>
>    import iterator from "sys:iterator";
>
>    class Derived extends Base {
>
>      [iterator]() {
>        super.doSomething(); // Works like a charm!
>      }
>    }
>
>This is IMO the best way forward.  It's generally useful beyond the use
>case presented here and does not use up a valuable free ASCII character.
> It also doesn't require any new symbolism since we already understand that
>brackets indicate computed property names.  Why were computed property
>names killed again?
>
>Kevin
>
>_______________________________________________
>es-discuss mailing list
>es-discuss at mozilla.org
>https://mail.mozilla.org/listinfo/es-discuss


More information about the es-discuss mailing list