`with` revisited and related to object extension literals
On 31 May 2012 11:33, T.J. Crowder <tj at crowdersoftware.com> wrote:
All,
I was going to lurk longer before raising this, and apologies if it's been raised before, but the discussion of object extension literals sort of brought it up.
TL;DR: I wonder if the object extension literal might reasonably become a fit-for-purpose
with
. For years I've thought thewith
problem could be solved relatively easily by using a leading dot (not an original thought, but I hesitate to even mention where I've seen it before -- VB) and presumably a different keyword. Now I wonder if we don't even need a keyword.The detail:
The current strawman supports
o.{ a: "foo", b = "bar" };
...where the first is [[DefineOwnProperty]] and the second is [[Put]]. The discussion has moved on a bit with people suggesting using semicolons and allowing calls as well:
o.{ a: "foo"; b = "bar"; c.f(); // e.g., o.c.f() };
or with parens:
o.( a: "foo"; b = "bar"; c.f(); // e.g., o.c.f() );
To me, that starts looking a lot like a series of statements rather than definitions/assignments -- and specifically, a lot like
with
.So that leads me to wonder about something along these lines:
o.{ .a: "foo"; // [[DefineOwnProperty]] .b = "bar"; // [[Put]] .c.f(); // E.g., o.c.f(); .d = .a; // E.g., o.d = o.a; .x.{ .y = 2; // E.g., o.x.y = 2; }; };
E.g., a combination of object extension literal and an improved
with
.-- T.J.
Sorry, a couple of points I should have made about the above:
-
I used {} rather than () because this is a block (thus
let
works within it). -
I originally envisioned this as a statement (of course, I was originally thinking we'd have a new keyword, until the object extension literal discussion), but it could be an expression; if so, presumably the result of the expression would be the object.
-
The leading dot makes tools support a bit simpler.
-
The leading dot seems, to me, to be more explicit than just having the first symbol on the left being implicitly a property the object. EIBTI
-
There would be a temptation to try to backfit this on object initializers as well, but I'd be worried about the confusion it creates (not least for parsers) supporting both syntaxes within an object initializer. If this new thing is an expression (see #2), there's no need, because o = {}.{ .a = 5; .b = .a; }; works just fine.
-- T.J.
On 31 May 2012 12:52, T.J. Crowder <tj at crowdersoftware.com> wrote:
- I originally envisioned this as a statement (of course, I was originally thinking we'd have a new keyword, until the object extension literal discussion), but it could be an expression; if so, presumably the result of the expression would be the object.
Note that, if this is an expression, then you are introducing a
variant of do'-expressions through the backdoor (i.e., a way to nest statements into expressions). That is a significant change to the language, so it only is an option if we agree to have
do'.
- The leading dot seems, to me, to be more explicit than just having the first symbol on the left being implicitly a property the object. EIBTI
I agree with that.
On 31 May 2012 12:12, Andreas Rossberg <rossberg at google.com> wrote:
On 31 May 2012 12:52, T.J. Crowder <tj at crowdersoftware.com> wrote:
- I originally envisioned this as a statement (of course, I was originally thinking we'd have a new keyword, until the object extension literal discussion), but it could be an expression; if so, presumably the result of the expression would be the object.
Note that, if this is an expression, then you are introducing a variant of
do'-expressions through the backdoor (i.e., a way to nest statements into expressions). That is a significant change to the language, so it only is an option if we agree to have
do'.
Indeed, though unintentionally. I think the two are closely related, but can be decided individually. FWIW, I have no strong opinion (not that matters!) on whether these should be expressions. Those who are deeper in the process can speak to that question rather more usefully than I. I do kind of like how them being expressions bypasses the question of extending object initializer syntax possibly past the breaking point (my #5).
-- T.J.
On May 31, 2012, at 4:12 AM, Andreas Rossberg wrote:
- The leading dot seems, to me, to be more explicit than just having the first symbol on the left being implicitly a property the object. EIBTI
I agree with that.
As I said in another thread, it's not going to happen because of the ASI hazard.
On 31 May 2012 19:24, David Herman <dherman at mozilla.com> wrote:
On May 31, 2012, at 4:12 AM, Andreas Rossberg wrote:
- The leading dot seems, to me, to be more explicit than just having the
first symbol on the left being implicitly a property the object. EIBTI
I agree with that.
As I said in another thread, it's not going to happen because of the ASI hazard.
Dave
Expand/link? How does this cause an ASI issue (that can't be solved)?
-- T.J.
On Thu, May 31, 2012 at 4:46 PM, T.J. Crowder <tj at crowdersoftware.com>wrote:
On 31 May 2012 19:24, David Herman <dherman at mozilla.com> wrote:
As I said in another thread, it's not going to happen because of the ASI hazard.
Dave
Expand/link? How does this cause an ASI issue (that can't be solved)?
I believe Dave is referring to this thread: www.mail-archive.com/[email protected]/msg16071.html
On 31 May 2012 22:17, Rick Waldron <waldron.rick at gmail.com> wrote:
On Thu, May 31, 2012 at 4:46 PM, T.J. Crowder <tj at crowdersoftware.com>wrote:
On 31 May 2012 19:24, David Herman <dherman at mozilla.com> wrote:
As I said in another thread, it's not going to happen because of the ASI hazard.
Dave
Expand/link? How does this cause an ASI issue (that can't be solved)?
I believe Dave is referring to this thread: www.mail-archive.com/[email protected]/msg16071.html
-- T.J.
Thanks Rick. For lurkers:
o.{ foo() // No semi .bar() // Is this o.bar()? or .bar() on the result of foo()? };
So we solve that, which is easily done. Could be ~. or .. or any of several other things, such as:
o.{ ~.a: "foo"; // [[DefineOwnProperty]] ~.b = "bar"; // [[Put]] ~.c.f(); // E.g., o.c.f(); ~.d = ~.a; // E.g., o.d = o.a; ~.x.{ ~.y = 2; // E.g., o.x.y = 2; }; };
Still offers all the benefits listed earlier, and in fact is possibly even more explicit. For ~. read any reasonably combination of symbols that we can make work syntactically.
The precise syntax is not as important as the concept. Basically, it seems
to me that object extension literals are really just a limited and implicit
with
, so rather than trying to solve a limited and implicit with
, we
should either solve the syntactic issues around a genuine, 21st-century
explicit with
that encompasses those same use cases, or the whole thing
(improved with
and object literal extensions) isn't worth bothering with
(which is a real possibility).
-- T.J.
Thanks Rick. For lurkers:
o.{ foo() // No semi .bar() // Is this o.bar()? or .bar() on the result of foo()? };
I've been following and have read back in the thread, but I'm not seeing a how ".bar()" would be allowed?
Point me in the right direction!
Rick Waldron wrote:
Thanks Rick. For lurkers: o.{ foo() // No semi .bar() // Is this o.bar()? or .bar() on the result of foo()? };
I've been following and have read back in the thread, but I'm not seeing a how ".bar()" would be allowed?
In the with example that Dave gave:
with (obj) {
foo() // no semi
.bar = 12
}
it's all allowed as in no syntax error (to correct via ASI) and no restricted production (to make line termination significant).
Over the years people have suggested reforming 'with' a la VB by requiring leading . before names meant to be looked up in the 'with' object instead of the scope chain. But that fails as Dave showed.
T.J. was suggesting that Dave's cascade proposal has the 'with' hazard, but it doesn't. No scope chain lookup. Therefore no need for leading ., ~. or any such noise.
On 1 June 2012 00:28, Brendan Eich <brendan at mozilla.org> wrote:
In the with example that Dave gave:
with (obj) { foo() // no semi .bar = 12 }
it's all allowed as in no syntax error (to correct via ASI) and no restricted production (to make line termination significant).
Over the years people have suggested reforming 'with' a la VB by requiring leading . before names meant to be looked up in the 'with' object instead of the scope chain. But that fails as Dave showed.
T.J. was suggesting that Dave's cascade proposal has the 'with' hazard, but it doesn't. No scope chain lookup. Therefore no need for leading ., ~. or any such noise.
/be
What is "Dave's cascade proposal"? You mean throwing function calls into the existing object extension literal? Or...?
I'd appreciate it if characterizations like "noise" were done...carefully. We're all here because we love JS and want to improve it and move it forward.
Thanks,
-- T.J.
T.J. Crowder wrote:
On 1 June 2012 00:28, Brendan Eich <brendan at mozilla.org <mailto:brendan at mozilla.org>> wrote:
In the with example that Dave gave: with (obj) { foo() // no semi .bar = 12 } it's all allowed as in no syntax error (to correct via ASI) and no restricted production (to make line termination significant). Over the years people have suggested reforming 'with' a la VB by requiring leading . before names meant to be looked up in the 'with' object instead of the scope chain. But that fails as Dave showed. T.J. was suggesting that Dave's cascade proposal has the 'with' hazard, but it doesn't. No scope chain lookup. Therefore no need for leading ., ~. or any such noise. /be
What is "Dave's cascade proposal"? You mean throwing function calls into the existing object extension literal? Or...?
Dave's cascade proposal:
blog.mozilla.org/dherman/2011/12/01/now-thats-a-nice-stache
I'd appreciate it if characterizations like "noise" were done...carefully. We're all here because we love JS and want to improve it and move it forward.
No offense -- I called leading . noise too (and I've toyed with it as somehow helping 'with' if forbidden at start of line, e.g.).
I believe it's a mistake to theory-patch, however. You were following the reform-with path which leads to leading dot. Then the ASI (lack of it, as usual -- "nega-ASI" :-P) problem reared its head. Then you mooted ~. This approach has a smell, in science and engineering. I say this without meaning offense again, since I've done it myself (especially in code, so there's a code patch too -- and technical debt if not a user-facing "noise" spike).
On 1 June 2012 00:51, Brendan Eich <brendan at mozilla.org> wrote:
Dave's cascade proposal:
blog.mozilla.org/**dherman/2011/12/01/now-thats-**a-nice-stacheblog.mozilla.org/dherman/2011/12/01/now-thats-a-nice-stache
Thanks. With a great deal of respect, I'm not seeing how that isn't
"with-lite" with a magic LHS. Indeed, how is it less confusing (and less
implicit) than the existing with
? Re the recurring array example: Which
pop
is it? One specific to the object? A local? Something in the
containing scope? A global? Why is the magic constrained to the LHS?
I believe it's a mistake to theory-patch, however. You were following the
reform-with path which leads to leading dot. Then the ASI (lack of it, as usual -- "nega-ASI" :-P) problem reared its head. Then you mooted ~. This approach has a smell, in science and engineering. I say this without meaning offense again, since I've done it myself (especially in code, so there's a code patch too -- and technical debt if not a user-facing "noise" spike).
I'm not seeing (smelling?) a smell. Making free symbols be implicit
property lookups has an error-prone history (vis: with
as-was), so my
thought was: Make it explicit. I'm not by far the first. Dave pointed out
that ASI causes an issue with the specific syntax I mentioned, so I
addressed that -- while making the point that the specific syntax was not
the main thrust of the argument. Surely we can respond to reasonable
syntactic flags without invalidating the broader concept?
All of which is somewhat beside the point. The main point is that it seems
like the object extension literal proposal (esp. when combined with the
cascade proposal) is another form of with
, with similar issues, plus some
confusion with object initializers. My main point is: Perhaps the issues
arising are in part because of the magic, and perhaps either A) Making it
explicit helps, or B) The magic ain't worth it.
Let's take another look:
var foo = "bar";
this.{ foo = "baz" yow = "hello" baz = foo };
What's foo
? Is it still "bar" or is it "baz"? What's this.baz
? Is it
"bar" or "baz" or did the code throw or...? Contrast with:
var foo = "bar";
this.{ ~.foo = "baz"; ~.yow = "hello"; ~.baz = foo; };
EIBTI. No confusion between foo and ~.foo. There's a distinction between being explicit, being clear, and adding noise.
Again I want to emphasize that the precise syntax is not the point. It
could be "~" or ">" or "^" or any of several other things instead of "~".
(I quite like the ~, though, as it happens.) Being explicit, and deciding
to either do, or not do, with
-lite, is the point.
(And I want to emphasize that I'm clear I'm a newcomer amongst giants, although not remotely a newcomer to designing solutions; and I have a lot of respect for the giants in the room. Just trying to contribute, to be helpful; not to be difficult.)
-- T.J.
T.J. Crowder wrote:
On 1 June 2012 00:51, Brendan Eich <brendan at mozilla.org <mailto:brendan at mozilla.org>> wrote:
Dave's cascade proposal: http://blog.mozilla.org/dherman/2011/12/01/now-thats-a-nice-stache/
Thanks. With a great deal of respect, I'm not seeing how that isn't "with-lite" with a magic LHS. Indeed, how is it less confusing (and less implicit) than the existing
with
? Re the recurring array example: Whichpop
is it? One specific to the object?
Yes, and only that.
A local?
No. This is a special form, the expressions you can cascade in the {} are restricted. The leading identifier is always only a property reference in the head object.
Something in the containing scope?
Nope.
A global?
No way ;-).
Why is the magic constrained to the LHS?
Because that's the intended useful magic. This is a new special form, as Mark pointed out for factoring
o.foo = 1; o.bar = 2; o.baz()
into
o.{foo = 1; bar = 2; baz()};
(I squished on one line here.)
I believe it's a mistake to theory-patch, however. You were following the reform-with path which leads to leading dot. Then the ASI (lack of it, as usual -- "nega-ASI" :-P) problem reared its head. Then you mooted ~. This approach has a smell, in science and engineering. I say this without meaning offense again, since I've done it myself (especially in code, so there's a code patch too -- and technical debt if not a user-facing "noise" spike).
I'm not seeing (smelling?) a smell.
Theory patching analogue: add a funny but unambiguous character before the . to rescue the reform-with theory. But you agree we're not reforming 'with' and Dave's cascade syntax has nothing to do with 'with' (see above).
Making free symbols be implicit property lookups has an error-prone history (vis:
with
as-was),
Only if those free symbols are looked up in the scope chain to which the 'with'-head object has been prefixed. There is no hazard in a shorthand derived from good old dot.
so my thought was: Make it explicit. I'm not by far the first. Dave pointed out that ASI causes an issue with the specific syntax I mentioned, so I addressed that -- while making the point that the specific syntax was not the main thrust of the argument. Surely we can respond to reasonable syntactic flags without invalidating the broader concept?
No, we do not agree on what you call the "broader concept". Let's settle that first before syntax arguments.
The theory does not need a ~ patch if there is no 'with' hazard. Dave defined the proposal so that there is not. Are you concerned that there is an appearance of a hazard, due to
obj . { foo = ...
(I spaced things out and left off the right context on purpose). IOW, because if one ignores obj and the dot, we have what looks like a block, which starts with what looks like a free variable reference, foo?
I get that. It's why I argued for () instead of {}. But this is a readability or usability issue, so again I wouldn't try patching with leading ~. under the {} bracketing. And note that it's not a 'with'-like situation in any case -- no scope chain lookup (only what might be the appearance of that).
All of which is somewhat beside the point. The main point is that it seems like the object extension literal proposal (esp. when combined with the cascade proposal) is another form of
with
, with similar issues, plus some confusion with object initializers.
Let's be precise. You keep bringing 'with' up but it's not relevant to the cascade proposal, going by Dave's definitions. If you have the "appearance of 'with'" concern I call out above, let's argue about that. It's a good one (again it is why I preferred () a day or so ago).
My main point is: Perhaps the issues arising are in part because of the magic, and perhaps either A) Making it explicit helps, or B) The magic ain't worth it. (B) certainly could be the case. Deciding is art not science.
(A) is not constrained to be ~. or any such prefix if the problem is "appearance of 'with'" even thought this new special form was designed not to extend the scope chain. We should argue about the predicate problem, not about explicit patches to fix it.
On 1 June 2012 01:40, Brendan Eich <brendan at mozilla.org> wrote:
Let's be precise. You keep bringing 'with' up but it's not relevant to the cascade proposal, going by Dave's definitions. If you have the "appearance of 'with'" concern I call out above, let's argue about that. It's a good one (again it is why I preferred () a day or so ago).
Yes, that's my concern. Something that looks almost exactly like the old
with
, complete with implicit magic free symbol resolution, worries me. I
"keep" bringing up with
because it's implicit in the proposals. It's not
something I'm adding, I'm just shining a light on it. This is more true of
the cascade than object extension literals, but the inclusion of things
that look like assignments in object extension literals makes it true of
them as well.
The only place that immediately comes to mind where free symbols aren't currently resolved relative to the scope chain is the property name literals in object initializers, and they have a sufficiently distinct syntax (using the colon) that they're fairly distinct.
Separating the two distinct things (extension literals and cascade) out:
Object extension literals:
var a = "foo"; o.{ a = "bar" };
The lack of any kind of qualifier on the a
makes it problematic, to my
mind. Yes, there's that special .{ ... } syntax, but it's at a sufficient
remove from the assignment that it's asking for trouble. Perhaps this could
be solved without a with
-like structure by using something other than =,
to maintain the distinct nature that object initializers have. E.g.,
var a = "foo"; o.{ a: "bar", // [[DefineOwnProperty]] b:= "baz" // [[Put]] };
Now it doesn't look like an assignment any more. It echoes object initializer syntax. You could even read := as "define or put". And it has the advantage it could be harmlessly back-fitted on object initializers (er, I think -- I'm not a grammar god like AWB).
Now the cascade:
array.{ pop() pop() };
That looks like with
, it acts like with
, and it seems to have the same
motivation as with
: To avoid writing array
repeatedly. (I'm with Dave
on his point about the fragility of function chaining, btw.) I understand
that the proposal for it says pop
must be resolved relative to array
(unlike with
, where it could be anywhere on the scope chain), but it's
just way too similar. If we're going to do with
, let's do it. I might
want to avoid writing array
repeatedly on the RHS, too. (No RHSs in the
above, granted.)
Anyway, faced with two proposals with with
-like features, it seemed
reasonable to point that out, to suggest how the issues with both could be
resolved with an explicit form of with
. I'm a big fan of explicitness,
and a big fan of using a single solution to address multiple goals. But
it's just one way to go.
-- T.J.
On May 31, 2012, at 5:30 PM, T.J. Crowder wrote:
On 1 June 2012 00:51, Brendan Eich <brendan at mozilla.org> wrote: Dave's cascade proposal:
blog.mozilla.org/dherman/2011/12/01/now-thats-a-nice-stache
Thanks. With a great deal of respect, I'm not seeing how that isn't "with-lite" with a magic LHS.
There's no magic at all. The LHS is not an expression; there's no variable resolution involved. The problem with with
is that it captures all variable lookups anywhere in any nested expression. That's not the case with the cascade proposal. Furthermore, with
injects an object into the scope chain, so a variable lookup might end up either on the object or elsewhere in the scope chain. Again, not the case here. You can always tell statically which parts of the syntax correspond to the object and which things are just variables.
I'm not saying I'm 100% enthusiastic about the cascade proposal as is. In fact, I think we're wasting a ton of time on this area when we have more important things to work on. And no form of mustache is happening in ES6 anyway. It's been demoted to strawman; it never had consensus; it's not fully baked.
Indeed, how is it less confusing (and less implicit) than the existing
with
? Re the recurring array example: Whichpop
is it? One specific to the object? A local? Something in the containing scope? A global? Why is the magic constrained to the LHS?
There is no mixing of scope and object lookup in the cascade proposal. None at all.
I'm not seeing (smelling?) a smell. Making free symbols be implicit property lookups has an error-prone history (vis:
with
as-was), so my thought was: Make it explicit. I'm not by far the first. Dave pointed out that ASI causes an issue with the specific syntax I mentioned, so I addressed that -- while making the point that the specific syntax was not the main thrust of the argument. Surely we can respond to reasonable syntactic flags without invalidating the broader concept?
What Brendan is saying is that the cascades proposal does address the broader concept: being able to multiple property accesses without having to rename the target object, and in a way that doesn't defeat lexical scope. Now, you proposed a syntax that doesn't work because of ASI. Then you tossed in a ~ to address that. Sorry, but you don't design syntax by throwing more sigils at it till it's unambiguous. That way lies line noise.
All of which is somewhat beside the point. The main point is that it seems like the object extension literal proposal (esp. when combined with the cascade proposal) is another form of
with
,
No, it's just not. There are valid issues with all the variations on "mustache," but "being another form of with
" is not one of them. Some good objections have been raised on this thread:
https://gist.github.com/9a6d60e9c15ac4239b3d
But the problem with with
is that it screws up lexical scope. None of the mustache proposals, including the cascades one, screws up lexical scope.
Again I want to emphasize that the precise syntax is not the point. It could be "~" or ">" or "^" or any of several other things instead of "~". (I quite like the ~, though, as it happens.) Being explicit, and deciding to either do, or not do,
with
-lite, is the point.
Just please stop saying that it's like with
. It's totally unlike with
, and you'll only confuse people by saying it is. I'm not sure if you've understood the intended semantics, but it's simply nothing like with
. You can disagree with the feature, but stick to technically valid arguments.
(And I want to emphasize that I'm clear I'm a newcomer amongst giants, although not remotely a newcomer to designing solutions; and I have a lot of respect for the giants in the room. Just trying to contribute, to be helpful; not to be difficult.)
Hey, no stress -- always happy to have input. Just please, no more bogus comparisons to with
.
On May 31, 2012, at 7:08 PM, T.J. Crowder wrote:
On 1 June 2012 01:40, Brendan Eich <brendan at mozilla.org> wrote: Let's be precise. You keep bringing 'with' up but it's not relevant to the cascade proposal, going by Dave's definitions. If you have the "appearance of 'with'" concern I call out above, let's argue about that. It's a good one (again it is why I preferred () a day or so ago).
Yes, that's my concern. Something that looks almost exactly like the old
with
, complete with implicit magic free symbol resolution, worries me. I "keep" bringing upwith
because it's implicit in the proposals. It's not something I'm adding, I'm just shining a light on it.
This is a misunderstanding. There's no such thing as "free symbol resolution." There are "free variables" and there is "variable resolution" but "free symbol resolution" doesn't mean anything.
In the cascade proposal, the LHS of each item contains no variables. It's just a property name used on the target object. There's never any ambiguity as to whether it might be looked up on the object or looked up in the lexical environment.
The RHS of each assignment is just an ordinary expression, and is looked up in the ordinary lexical environment.
This is nothing like with
. Your protestations are generating more heat than light.
This is more true of the cascade than object extension literals, but the inclusion of things that look like assignments in object extension literals makes it true of them as well.
Absolutely not. You can argue that the cascade syntax is more confusing -- and it may well be -- but semantically it's totally the same as the other mustache proposals (other than the additional ability to call methods as well, but that also introduces no semantic issues with scope).
Now the cascade:
array.{ pop() pop() };
That looks like
with
, it acts likewith
,
No, it doesn't, and it would be really helpful if you would try to understand why it doesn't.
T.J. Crowder wrote:
On 1 June 2012 01:40, Brendan Eich <brendan at mozilla.org <mailto:brendan at mozilla.org>> wrote:
Let's be precise. You keep bringing 'with' up but it's not relevant to the cascade proposal, going by Dave's definitions. If you have the "appearance of 'with'" concern I call out above, let's argue about that. It's a good one (again it is why I preferred () a day or so ago).
Yes, that's my concern. Something that looks almost exactly like the old
with
, complete with implicit magic free symbol resolution, worries me. I "keep" bringing upwith
because it's implicit in the proposals. It's not something I'm adding, I'm just shining a light on it.
No, you're just rehashing a concern based on appearances. Operationally there is nothing 'with'-like in cascades. Please stop asserting more than "looks" by adding semantic nonsense such as "complete with implicit magic free symbol resolution".
David Herman wrote:
Now the cascade:
array.{ pop() pop() };
That looks like
with
, it acts likewith
,No, it doesn't, and it would be really helpful if you would try to understand why it doesn't.
So the key here is prototype chain vs. scope chain. 'with' extends the scope chain:
with (array) { pop() pop() };
so the two chains look like this:
Object.prototype <---------------+
^ \
| \
Array.prototype : ^ : | | HEAD -> array -- next-outer-scope --> global
where HEAD is the head of the scope chain. The [[Prototype]]-linked chain points upward, the scope chain left-to-right. Of course there is no next-outer-scope intrinsic property of array, that would make a pigeon-hole problem (with (array) (function () { with (array) {...} }), e.g.)
Cascades do nothing to the scope chain and desugar
array.{ pop() pop() };
to
array.pop(); array.pop();
For the example, with pop the method on Array.prototype, of course there is no difference. Even if a custom 'pop' property were added to just array, shadowing Array.prototype.pop, no difference. But the crucial difference is when array is not even an array, or there's a typo:
array.{ pop() flop() };
Unlike the 'with' case, flop() in the cascade is desugared to array.flop(), so there's a type error trying to invoke the undefined value, absent any 'flop'-named property with a callable value in array itself, or on its prototype chain.
In the 'with' case, a global
var flop = function () { return "haha"; }
assigned before the 'with' will make the equivalent 'with'-based code compile and run -- but probably not as intended.
This may seem not much of a difference, but it's major not only due to the typo and array-not-an-Array-instance cases. The scope chain extension is costly and forces deoptimization in common implementations. And of course 'with' is banned in strict mode.
Dave, any other differences to spell out?
On May 31, 2012, at 9:31 PM, Brendan Eich wrote:
This may seem not much of a difference, but it's major not only due to the typo and array-not-an-Array-instance cases. The scope chain extension is costly and forces deoptimization in common implementations. And of course 'with' is banned in strict mode.
Dave, any other differences to spell out?
That's pretty much it, but I'd also point out one more important consequence: by with
adding an object to the scope chain, it pollutes scope with potentially unintended properties of the object -- or any of its prototypes. So when you have a variable reference in a sub-expression, you may think you know what it refers to but it could be captured by the with
object or one of its properties.
var obj = {
log: console.log.bind(console),
foo: function() { Object.prototype.bar = "captured" }
};
var bar = "local variable";
with (obj) {
log(bar); // local variable
foo();
log(bar); // captured
}
Whereas with cascades, you'd get:
var obj = {
log: console.log.bind(console),
foo: function() { Object.prototype.bar = "captured" }
};
var bar = "local variable";
with (obj) {
log(bar); // local variable
foo();
log(bar); // local variable
}
On May 31, 2012, at 9:50 PM, David Herman wrote:
...but it could be captured by the
with
object or one of its properties.
s/properties/prototypes/
On May 31, 2012, at 9:50 PM, David Herman wrote:
Whereas with cascades, you'd get:
var obj = { log: console.log.bind(console), foo: function() { Object.prototype.bar = "captured" } }; var bar = "local variable"; with (obj) { log(bar); // local variable foo(); log(bar); // local variable }
Oh for crying out loud. Of course I meant:
var obj = {
log: console.log.bind(console),
foo: function() { Object.prototype.bar = "captured" }
};
var bar = "local variable";
obj.{
log(bar); // local variable
foo();
log(bar); // captured
}
Right, that capture-in-prototype case does not differ due to both cascade desugaring and 'with' searching the head object including its prototype chain.
But with a deeper scope chain, and bar not bound in the innermost scope, then 'with' allows an evil interloping function to shadow (or delete if configurable) along the scope chain.
Brendan Eich wrote:
you're just rehashing a concern based on appearances
which (I want to be clear; sorry for harshing on the 'with' point) is a valid concern. We should discuss it directly, no 'with'-semantics mixed in.
On 1 June 2012 03:23, David Herman <dherman at mozilla.com> wrote:
There is no mixing of scope and object lookup in the cascade proposal. None at all.
You're talking the technical details. I'm talking appearance and expectation in the eyes of developers.
Just please stop saying that it's like
with
. It's totally unlikewith
, and you'll only confuse people by saying it is. I'm not sure if you've understood the intended semantics, but it's simply nothing likewith
. You can disagree with the feature, but stick to technically valid arguments.
....
Hey, no stress -- always happy to have input. Just please, no more bogus comparisons to
with
.
Could we please avoid derogatory terms like "bogus"? I'm talking about what people see when they look at code (more below). That's a valid argument. You can disagree with it without deriding it.
You're quite right that I shouldn't have said it acts like with
,
because of course, it's been clearly defined not to. I should have said
that it looks like it acts like it, or just better yet just stuck with
"looks." Sorry, it was late.
On 1 June 2012 03:30, David Herman <dherman at mozilla.com> wrote:
This is a misunderstanding. There's no such thing as "free symbol resolution." There are "free variables" and there is "variable resolution" but "free symbol resolution" doesn't mean anything.
I should have said "token", or possibly "identifier," not "symbol".
In the cascade proposal, the LHS of each item contains no variables.
I didn't say it did.
Now the cascade:
array.{ pop() pop() };
That looks like
with
, it acts likewith
,No, it doesn't, and it would be really helpful if you would try to understand why it doesn't.
I do understand how you want it to work, how you've defined it. I'm clear
on that: The identifiers are property names, looked up on the object in
question in the usual way; they are not to be resolved by the scope chain.
A freestanding foo
outside the mustache is completely unrelated to a
freestanding foo
within the mustache. I get it.
I'm saying that's not what I see when I look at it, and not what I think most developers will see, because -- and correct me if I'm wrong, it's certainly been known! -- the only other place where that's true is an object initializer, isn't it? I believe everywhere else, an identifier that isn't a reserved word, standing free, is resolved via the scope chain. Object initializers look enough unlike step-by-step code (even though they are processed in source order) that they aren't confusing.
Apologies for apparently having given the impression I didn't understand how you defined cascades to work. We could have avoided some wasted time if I'd made that clear.
If the cascade proposal is not going forward in its current form any time soon, let's shelve this conversation. Bigger fish to fry, as you said. If you'd like the final word, though, I'm happy for you to have it.
-- T.J.
On 1 June 2012 06:05, Brendan Eich <brendan at mozilla.org> wrote:
Brendan Eich wrote:
you're just rehashing a concern based on appearances
which (I want to be clear; sorry for harshing on the 'with' point) is a valid concern. We should discuss it directly, no 'with'-semantics mixed in.
/be
Yes, very useful. I'll stick to things like "to me, the syntax makes it
look like those identifiers would be resolved via the scope chain" and
such. Won't mention with
.
I'm a bit worried that people may have thought I was being derisive by
talking about with
, and that that may have raised hackles. I wasn't. I
don't think with
is a flawed concept at all (I recognize many do), so I
don't use it derisively. I agree with, I think, the majority here including
(if I'm not mistaken) your own good self that JS's original with
had
serious issues, which in my view were down to it using freestanding
identifiers, intermixing object property resolution and scope chain
resolution. But I have no problem with the concept in a different form.
So in summary and (largely) in closing:
-
I quite like the idea of the cascade proposal, because like Dave (I think?) I find the way cascades are currently done (a'la jQuery, via
return this
) less than ideal. -
My concerns with it relate to freestanding identifiers and how that looks. See earlier note to Dave.
-
I think that concern can be dealt with without going to a
with
-like structure. -
I also think they could be dealt with via a new
with
-like structure that did not put an object at the top of the scope chain, but instead introduced a placeholder token for the object reference as purely syntactic sugar (~. or similar). To me there's a lot of use there, including cascades. But I seem to be alone. :-) I find that a bit odd, given how similar to that the goals of the cascade sugar seem to be, but if I'm on my own, I'm on my own.
Best,
-- T.J.
No, you are not alone.
Mustache and cascade are interesting but maybe not extremely, extremely usefull.
Then as people have tried since years, I did write too a 'with'-like
proposal in strict mode, I already sent it some time ago and got 0
feedback, maybe I did not present it the right way, it has almost
nothing to do with the usual 'with' (which I find so strange that could
never figure out how this could be used), it's somewhere the contrary,
the concept is about the ability of binding things simply, not about
making incredible mix-up of accessing/defining properties/var/bindings,
so here it is again, not sure it can fit what you want but I have added
more examples to show what it could simplify, and changed the title,
it's not a 'with' revival, but a 'with' redesign, and then if 'with' is
confusing (or not liked) it can be called another name :
gist.github.com/edd064e5b29e67ebe493
It's a modest 'essai' (perfectible, maybe containing wrong or impossible things) so if it has to be destroyed, please be a little indulgent, at least I don't think one could say that the concepts behind it are not (very) usefull.
Le 01/06/2012 12:09, T.J. Crowder a écrit :
On Jun 1, 2012, at 2:54 AM, T.J. Crowder wrote:
Hey, no stress -- always happy to have input. Just please, no more bogus comparisons to
with
.Could we please avoid derogatory terms like "bogus"? I'm talking about what people see when they look at code (more below). That's a valid argument. You can disagree with it without deriding it.
Not deriding; it wasn't clear to me that your argument had to do with perception rather than semantics. I was responding to the words you said ("that's with-lite", "acts like with"). I was trying to be friendly, and failed -- where I come from "bogus" is not derogatory, it just means "invalid" without being debate-club nerdcore. And I do take issue with the analogy to with
. But I apologize for coming down too hard. These memes spread easily and they spread fast, so I really wanted to head off any confusion that we would ever specify something like with
.
In the cascade proposal, the LHS of each item contains no variables. I didn't say it did.
It was your use of the word "free" that confused me -- see below...
A freestanding
foo
outside the mustache is completely unrelated to a freestandingfoo
within the mustache. I get it.
Fair enough!
I'm saying that's not what I see when I look at it, and not what I think most developers will see, because -- and correct me if I'm wrong, it's certainly been known! -- the only other place where that's true is an object initializer, isn't it? I believe everywhere else, an identifier that isn't a reserved word, standing free, is resolved via the scope chain.
Oh, you're using "free" in a different way than I'm accustomed to. (A "free variable" is a variable reference that is not bound, or not bound in a particular context.) That's part of what threw me off.
So yeah, your objection is similar to Mikeal Rogers' objection in the gist thread I linked to before:
https://gist.github.com/9a6d60e9c15ac4239b3d#gistcomment-337536
I actually agree with that. The issue here is that to understand that the LHS of each item corresponds to the object rather than scope, you have to figure out that you're underneath a mustache. That's a reasonable objection.
I just take issue with the over-broad analogy to with
. The problem with with
is that it's statically undecidable whether any variable in the body is bound by the object or by something else in the scope chain.
Apologies for apparently having given the impression I didn't understand how you defined cascades to work. We could have avoided some wasted time if I'd made that clear.
And I apologize for reacting so strongly. It's just that with
is anathema to many JS developers (for good reason!), and it's an easy smear that gets used loosely to disregard proposals or even ES6 writ large.
On 1 June 2012 18:02, David Herman <dherman at mozilla.com> wrote:
I just take issue with the over-broad analogy to
with
. The problem withwith
is that it's statically undecidable whether any variable in the body is bound by the object or by something else in the scope chain.
Yeah, at least, it is with JS's current with
.
And I apologize for reacting so strongly. It's just that
with
is anathema to many JS developers (for good reason!), and it's an easy smear that gets used loosely to disregard proposals or even ES6 writ large.
Yes, sorry, I was very slow to pick up on that connotation (I don't share
a negative view of with
as a concept; I agree about the issues with
JS's old/current with
and never use it because of them). The penny
finally dropped when I was replying later to Brendan. Talk about causing
inadvertent offense.
Anyway, all clear now, and thanks again for listening!
-- T.J.
T.J. Crowder wrote:
On 1 June 2012 18:02, David Herman <dherman at mozilla.com <mailto:dherman at mozilla.com>> wrote:
I just take issue with the over-broad analogy to `with`. The problem with `with` is that it's statically undecidable whether any variable in the body is bound by the object or by something else in the scope chain.
Yeah, at least, it is with JS's current
with
.And I apologize for reacting so strongly. It's just that `with` is anathema to many JS developers (for good reason!), and it's an easy smear that gets used loosely to disregard proposals or even ES6 writ large.
Yes, sorry, I was very slow to pick up on that connotation (I don't share a negative view of
with
as a concept; I agree about the issues with JS's old/currentwith
and never use it because of them). The penny finally dropped when I was replying later to Brendan. Talk about causing inadvertent offense.Anyway, all clear now, and thanks again for listening!
Thanks for writing -- I think between your point about the left-hand sides embedded in a cascade looking "free" and Mikeal's point on the gist Dave cited, I am not whole-hog in favor of cascades.
It's good to thrash such designs in es-discuss and see if we can get to something promising. Cascades have some promise still in my view (Dart went for them) but they also seem marginal, in the YAGNI sense, and they add comprehension complexity and therefore (for some) confusion about what's being assigned.
I wouldn't try to rescue them with LHS prefixes. Among other reasons I think TC39 and the large anti-grawlix crowd won't go for any such ~.LHS idea.
All,
I was going to lurk longer before raising this, and apologies if it's been raised before, but the discussion of object extension literals sort of brought it up.
TL;DR: I wonder if the object extension literal might reasonably become a fit-for-purpose
with
. For years I've thought thewith
problem could be solved relatively easily by using a leading dot (not an original thought, but I hesitate to even mention where I've seen it before -- VB) and presumably a different keyword. Now I wonder if we don't even need a keyword.The detail:
The current strawman supports
o.{ a: "foo", b = "bar" };
...where the first is [[DefineOwnProperty]] and the second is [[Put]]. The discussion has moved on a bit with people suggesting using semicolons and allowing calls as well:
o.{ a: "foo"; b = "bar"; c.f(); // e.g., o.c.f() };
or with parens:
o.( a: "foo"; b = "bar"; c.f(); // e.g., o.c.f() );
To me, that starts looking a lot like a series of statements rather than definitions/assignments -- and specifically, a lot like
with
.So that leads me to wonder about something along these lines:
o.{ .a: "foo"; // [[DefineOwnProperty]] .b = "bar"; // [[Put]] .c.f(); // E.g., o.c.f(); .d = .a; // E.g., o.d = o.a; .x.{ .y = 2; // E.g., o.x.y = 2; }; };
E.g., a combination of object extension literal and an improved
with
.-- T.J.