Some questions about Private Name Objects (Kevin Smith)
Joseph Spencer
js.developer.undefined at gmail.com
Fri Sep 14 22:53:31 PDT 2012
I was going to say that I completely agree with Brendan on this:
>>> 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.
As a javascript developer looking at this new feature, and really having
never dealt with default parameter values very much outside of PHP
(where you're pretty much limited to literals for default values), I
would expect that default values in javascript would have complete
access to the inner scope.
I think the approach of looking at default parameters as a way to avoid
short-circuiting (as BE mentioned) makes a lot of sense, and is rather
conservative.
Old way:
function play(sound, player){
var _sound = sound || "boo";
var _player = player || new Player();
return _player;
function Player(){
this.play = function(){return _sound};
}
}
New way:
function play(sound = "boo", player = new Player()){
return player;
function Player(){
this.play = function(){return sound};
}
}
It does seem slightly incomplete though. I mean, there still isn't a
guarantee that the incoming type will match.
Old way:
play(false, false).play() //error
New way:
play(false, false).play() //error
Seems like one would still have to short-circuit, unless you provide a
mechanism to validate the arguments.
I would expect, that on the initial declaration of the function, the
type of the default value would be determined with some sort of
pre-check (and possibly limiting the type to PrimaryExpressions). Then
on any call, the incoming argument type would be evaluated against the
default return type, else fallback to using the initial RHS return type
for the value.
The problem with default parameter values that are evaluated at
execution time, is that you need to provide a
way for the RHS to validate the argument, otherwise one still may be
required to validate incoming args anyway, thus defeating the purpose of
default values.
-Joe
On Fri, 2012-09-14 at 15:05 -0700, Brendan Eich wrote:
> Was there more? No uncited text from you.
>
> /be
>
> Joe Spencer wrote:
> > 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
> > _______________________________________________
> > es-discuss mailing list
> > es-discuss at mozilla.org
> > https://mail.mozilla.org/listinfo/es-discuss
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120914/4ff941e7/attachment-0001.html>
More information about the es-discuss
mailing list