On "I got 99 problems and JavaScript syntax ain't one"

# David Bruant (14 years ago)

Le 04/10/2011 15:43, Kyle Simpson a écrit :

I'm sorry David, I just have to express a dissenting opinion here.

There is no reason to be sorry. As I said at the end, we are different within the same community. We have different need and views and consequently, sometimes disagree. That's fine, let's debate!

While I could see that "better tooling!" would be a positive side-effect of some syntax suggestions, I think it's a overreaching idea to consider such a main argument for adding new syntax.

You make a compelling argument of how tooling could benefit from the new syntax, sure. But it misses a few things:

  1. The readability of the language in environments where such tooling doesn't or can't really exist.
  2. Syntax highlighting of 1-2 char operators is far less visually helpful than syntax highlighting of method names, etc.
  3. Not all developers use a unified toolset for JavaScript (compared to say .NET where the vast majority use VS)

For #1, I personally think |> looks awful. I hate it. I wouldn't use it. And I'm less than entranced by the idea that I might have to read others' code with such confusing looking operators in it. Only if all the tools I was using to read & write JS were capable of somehow making that syntax useful/beautiful instead of ugly would your argument hold much water for me. But that's just opinion and preference.

For #2, which kinda goes with #1, I'm concerned that the readability (even with syntax highlighting) of the language as a whole will take a dip for several years as developers re-adjust to the new syntax. Syntax highlighting is often seen as a way to help the readability of a language, but syntax highlighting for new weird unfamiliar operators isn't going to help much at all.

By "syntax", I meant "things that provides guarantees program-wise". I didn't take program readibility in consideration. For instance, I do not think that addition of only 1-2 char operators is the best idea. Using keywords like "extends" sounds like a good idea and maybe a good alternative to <| (that apparently a lof of people are reluctant to) My point was positive about the addition of things that offer guarantees on the program. I talked about syntax without opinion of which syntax is good and which isn't. Readability is a different concern. Which should be addressed, I agree, but which is different from my need (having a language that can be more easily analysed). As far as I'm concerned, anything unambiguous will be enough.

Also, in all honesty, I think that it's hard to tell now things about readability. We are all highly influenced by current syntax and no one knows what newcomers to the language will find beautiful and ugly in 5 years (am I too optimistic?) when browsers will have implemented the new syntax features.

Will it eventually get better? Sure, if we don't keep adding new syntax every edition, it'll eventually stabilize. But I don't look forward to the dip in readability for the short-term, for my own code and for everyone else's code that I read.

For #3, I don't use fancy IDE's at all. I use text editors at best. I use notepad, PSPad, and Sublime on windows. And on linux I use vi. I doubt any of those text editors are ever going to care to pick up on the syntactic nuances you suggest. Which is my bigger point. Just because tooling CAN benefit from new syntax, doesn't mean all (or even most) tooling WILL benefit. What we'll end up with is a broad range of support from none all the way up to super-awesome-happy-unicorns. So both the good and bad side of this is YMMV.

I agree. As you emphasis, my point was about potential and for sure there will be a transition period. JavaScript is not the first language which has syntax changes throughtout its history and tools adapted. Maybe the core tools or plugins, but tools adapted.

Factoring all those things in, I can't see how "new syntax==better tooling" is anything more than an auxiliary supporting argument.

New syntax could allow more accurate analysis of JavaScript. Better tools is (only) one potential consequence of this better analysis. Better performance is another.

And yeah, I concur with the "99 problems..." statement. Working with JavaScript every day for the better part of a decade, I can't say that JavaScript's syntax issues have ever really tripped me up. Poor API's trip me up all the time. Poor handling of async (which can be considered a syntax issue!) definitely trips me up regularly.

I heard [1] that "yield" will be of some help for this.

David

[1] blog.mozilla.com/dherman/2011/03/11/who-says-javascript-io-has-to-be-ugly

# David Bruant (14 years ago)

Le 04/10/2011 17:03, Andrea Giammarchi a écrit :

David, as I have tweeted before, syntax is a non problem, surely is not a problem now because you already have alternatives such CoffeeScript, GWT, Traceeur or any sort of transpiler you want ... do all these new syntax bring real benefits to JavaScript ?

I sent a message here explaining the necessity of a syntax construct for a reliable bind [1]. There is a need to investingate (one reply was very close from a solution) to make sure that such a thing is not possible in pure ES5 (without making Function.prototype.bind non-configurable), but that would be one such thing that no language compiling to JavaScript could emulate (since impossible in the language itself).

The prototype operator allows subclassing which was a long awaited feature and this is not doable in pure ES5 (without proto which IE has never supported). This doesn't require syntax, but the idea of the proto operator looks elegant to me (the idea, not necessarily the proposed syntax)

Having new syntax for modules is not necessary per se but would be great to programatically analyse the module itself.

But I agree that most other things may not be necessary for the language itself since they could be emulated in another non-syntaxy way (but I'd be interested in seeing the non-syntax equivalent to make sure syntax is not that helpful).

I am not sure, I never needed new syntax, and all I know is that what's needed now cannot be obtained via transpiler

Subclassing cannot be achieved (or requires to extend built-in which in some cases may not be what people want) since it's not possible in JavaScript itself.

at least not the performances problem you may face one day when things become a bit more complex ( just think about games )

A transpiler, CoffeeScript like stuff, can bring you already a simulation of block scope without problems and Mozilla is already working on Firefox tools able to debug CoffeeScript directly, rather than it's equivalent in JavaScript.

But it's a tool. Mozilla doesn't work on a CoffeeScript emulator. It keeps investing (as everyone) in making a JavaScript interpretor. And such an interpretor would benefit from language constructs which offers invariants since invariants often result in performance improvements. After his JSConf.eu talk on Garbage Collection, I discussed with Erik Corry who told me that strict mode helped a bit with performance (things related to scopes and eval). I would expect the same things from syntax operators: offering invariants which can help out with performance. As long as JavaScript is the only thing that web browsers natively understand, we need to improve the language itself, syntax included since it's the only element of the language that programmers can't replace.

This achievement is possible today, what's truly needed for performances, common patterns as String#format and all other things that could help us in shorter therms is not.

Last, but not least, I asked Brendan a question, and I better reasoned it in my blog. I have not showed any community petition about this topic, but unless you learned JavaScript this year I do believe there are so many things you need that syntax, if you got, cannot have same priority ... am I wrong ?

I agree with you, but syntax is one other problem as well.

I agree with you it's not one voice, I don't agree when you talk about syntax changes in other programming languages because 100% of them are not in the web, at least not in users browsers.

If a language is on the server side nobody cares much about these syntax changes because they can chose the version they want.

This is extremely true and this is the reason why ES.next will have an opt-in.

As you mention, JavaScript has the particularity of being the only "mobile code on the web" language. Any change to the language will require an opt-in. As I said above, there are a couple of things that need a syntax construct, so I think that changing the syntax is necessary, and consequently so is adding an opt-in. Since any syntax change requires an opt-in, I think we can agree that as many as many syntax changes as possible (and as necessary of course) should ship with ES.next (10 years from now, I don't want to see thousands of opt-ins)

As a side note, an opt-in is not necessary for each syntax change. ES5 brought getter and setter initialization syntax. There is no opt-in. The downside being that no one can use them until IE8 is dead. (I agree that no one really care of this one, but you get the point)

There are still services entirely based on PHP4, do they care about PHP 5.3 or 6 ? They will when necessary, when they can update their code.

Python 3000 has still poor support ... and even if server side only, you need a valid reason to choose Python 3 over 2.X because 80% of libraries out there are in Python 2 and these break in Python 3

JavaScript is the exception that confirms the rule about programming languages since is unique option for everybody.

We have done so well until now updating and enreaching it that we should understand that non breaking features are most likely the best way to go and the transition between JavaScript and SomethingDifferentOutOfES6 should be as smooth as possible, and possibly focused on what's truly needed now - not the syntax, not today, please.

When then? :-) It seems that there will always be something that we need to do that may not require syntax. But modules, for instance is something we need now as well. Subclassing has been long awaited too. And for both, providing syntax constructs sounds relevant.

David

[1] esdiscuss/2011-August/016395

# Andrea Giammarchi (14 years ago)

I am on mobile so it's short one ... subclassing does not need new syntax, it needs eventually a fix on Object.create or a similar method. However, subclassing will always suffer cross frame issues, isn't it so how a triangle can magically solve this specific problems is a mystery to me but I'll be happy to show examples you can reuse to simulate new syntax features :-)

On Tuesday, October 4, 2011, David Bruant <david.bruant at labri.fr> wrote:

Le 04/10/2011 17:03, Andrea Giammarchi a écrit :

David, as I have tweeted before, syntax is a non problem, surely is not a

problem now because you already have alternatives such CoffeeScript, GWT, Traceeur or any sort of transpiler you want ... do all these new syntax bring real benefits to JavaScript ?

I sent a message here explaining the necessity of a syntax construct for a

reliable bind [1]. There is a need to investingate (one reply was very close from a solution) to make sure that such a thing is not possible in pure ES5 (without making Function.prototype.bind non-configurable), but that would be one such thing that no language compiling to JavaScript could emulate (since impossible in the language itself).

The prototype operator allows subclassing which was a long awaited feature

and this is not doable in pure ES5 (without proto which IE has never supported). This doesn't require syntax, but the idea of the proto operator looks elegant to me (the idea, not necessarily the proposed syntax)

Having new syntax for modules is not necessary per se but would be great

to programatically analyse the module itself.

But I agree that most other things may not be necessary for the language

itself since they could be emulated in another non-syntaxy way (but I'd be interested in seeing the non-syntax equivalent to make sure syntax is not that helpful).

I am not sure, I never needed new syntax, and all I know is that what's

needed now cannot be obtained via transpiler

Subclassing cannot be achieved (or requires to extend built-in which in

some cases may not be what people want) since it's not possible in JavaScript itself.

at least not the performances problem you may face one day when things

become a bit more complex ( just think about games )

A transpiler, CoffeeScript like stuff, can bring you already a simulation

of block scope without problems and Mozilla is already working on Firefox tools able to debug CoffeeScript directly, rather than it's equivalent in JavaScript.

But it's a tool. Mozilla doesn't work on a CoffeeScript emulator. It keeps

investing (as everyone) in making a JavaScript interpretor. And such an interpretor would benefit from language constructs which offers invariants since invariants often result in performance improvements.

After his JSConf.eu talk on Garbage Collection, I discussed with Erik

Corry who told me that strict mode helped a bit with performance (things related to scopes and eval). I would expect the same things from syntax operators: offering invariants which can help out with performance.

As long as JavaScript is the only thing that web browsers natively

understand, we need to improve the language itself, syntax included since it's the only element of the language that programmers can't replace.

This achievement is possible today, what's truly needed for performances,

common patterns as String#format and all other things that could help us in shorter therms is not.

Last, but not least, I asked Brendan a question, and I better reasoned it

in my blog.

I have not showed any community petition about this topic, but unless you

learned JavaScript this year I do believe there are so many things you need that syntax, if you got, cannot have same priority ... am I wrong ?

I agree with you, but syntax is one other problem as well.

I agree with you it's not one voice, I don't agree when you talk about

syntax changes in other programming languages because 100% of them are not in the web, at least not in users browsers.

If a language is on the server side nobody cares much about these syntax

changes because they can chose the version they want.

This is extremely true and this is the reason why ES.next will have an

opt-in.

As you mention, JavaScript has the particularity of being the only "mobile

code on the web" language. Any change to the language will require an opt-in. As I said above, there are a couple of things that need a syntax construct, so I think that changing the syntax is necessary, and consequently so is adding an opt-in.

Since any syntax change requires an opt-in, I think we can agree that as

many as many syntax changes as possible (and as necessary of course) should ship with ES.next (10 years from now, I don't want to see thousands of opt-ins)

As a side note, an opt-in is not necessary for each syntax change. ES5

brought getter and setter initialization syntax. There is no opt-in. The downside being that no one can use them until IE8 is dead. (I agree that no one really care of this one, but you get the point)

There are still services entirely based on PHP4, do they care about PHP

5.3 or 6 ? They will when necessary, when they can update their code.

Python 3000 has still poor support ... and even if server side only, you

need a valid reason to choose Python 3 over 2.X because 80% of libraries out there are in Python 2 and these break in Python 3

JavaScript is the exception that confirms the rule about programming

languages since is unique option for everybody.

We have done so well until now updating and enreaching it that we should

understand that non breaking features are most likely the best way to go and the transition between JavaScript and SomethingDifferentOutOfES6 should be as smooth as possible, and possibly focused on what's truly needed now - not the syntax, not today, please.

When then? :-) It seems that there will always be something that we need to do that may

not require syntax. But modules, for instance is something we need now as well. Subclassing has been long awaited too. And for both, providing syntax constructs sounds relevant.

David

[1] esdiscuss/2011-August/016395

On Tue, Oct 4, 2011 at 3:16 PM, David Bruant <david.bruant at labri.fr>

wrote:

Le 03/10/2011 22:49, Andrea Giammarchi a écrit :

Dear All, while I had the opportunity to ask directly to Brendan Eich this

question, I would like to ask you 5 minutes of your precious time to understand common concerns from the JS community, summarized under my point of view in this post:

webreflection.blogspot.com/2011/10/dear-brendan-here-was-my-question.html < webreflection.blogspot.com/2011/10/dear-brendan-here-was-my-question.html

I would like to thank you in advance for your time and all possible

answers/considerations/questions you may come up with.

I have seen the sentence "I got 99 problems and JavaScript syntax ain't

one" on twitter (by @mikeal), reused in Brendan's slide of CapitolJS and at JSConf.eu.

Plenty of people seem to agree with this and I would like to take one

minute to justify why syntax is important in my opinion.

Currently, I can cite only one IDE that has decent JavaScript support:

WebStorm. And they have a very good completion suggestion engine. I have seen JavaScript IDEs stopping to analyse when coming across the (function(){...})(); pattern.

Why aren't there that many good JavaScript IDEs? Because JavaScript is

ridiculously hard to analyse. It is weakly typed, and highly dynamic. For the last months, I have given myself the challenge to come up with a program which analyse jQuery and is able to retrieve the API. This is really hard. Most of the API is added with calls to jQuery.extend.

Basically, a program would have to understand the semantics of

jQuery.extend. But also understand that the output of $('a') has such prototype object with such properties.

This is doable (since the WebStorm people do it), but very hard.

If people have a syntax operator to perform an extend operation, well,

that makes things infinitely easy to analyse, because it becomes part of the language.

Another example:

var o = Object.create(null);

What is the o? If Object.create has not been redefined, it's an object.

But it may be anything if Object.create has been redefined. Consequently, a JavaScript engine can never optimize this line (or may, but have to guard that Object.create hasn't been redefined which costs a little something)


var o = null <| {};

Here, the semantics of this line is guaranteed by the language since this

is syntax and not a function. Consequently, optimizations can be performed without risking to be compromised.

Syntax additions make the language easier to analyse (allowing better

tooling) and more stable so easier to optimize. Syntax may not be the concern of a part of the community, but is of another.

Also, I'd like to mention that I'm pro-syntax addition when it covers

things that would benefit from syntax (an extend operator, object literal additions...), but i won't feed discussions on syntax which do not bring anything else than readability, namely shorter function syntax. I have a preference, but do not care of the exact final syntax. I also do not really care of what the exact final syntax will be, but I do care that JavaScript contains more syntax for common patterns, especially the ones that helps analysis and optimizations.

The JavaScript community is not one voice and doesn't have one unique set

of needs. We use the language for different purposes. Some need crazy performance for awesome graphics/sound experience. Some need more stability to build tools (linters, IDE plugins, etc.). At JSconf.eu, Lea Verou mentionned during her talk that she loved Object.prototype.watch and that she wishes every browsers had this because it's helpful to write polyfills. Maybe it is time to restart the discussion on "observe" [1].

I wrote this paragraph because of the sentence "the only thing truly

needed by this community now" in your (Andrea) post.

"the only thing truly needed" does not exist. Maybe several people, maybe

the majority of people want this. But other want other things and as long as it's justified, TC39 should address all of them.

# Mikeal Rogers (14 years ago)

Maybe it's time for me to chime in.

While I find it facilitating that so much meaning is being found in my tweet I thought it might be productive to say what I actually meant by the comment.

JavaScript's current (ECMA5) syntax has never prevented me from building an application. I find coffeescript, and compile-to-js languages in general, an attempt to solve the wrong problem, because syntax isn't my problem.

There are things in the language that actively make it harder for me to build applications (64bit int & binary support being the biggest).

I'm now in the odd position of working with a lot of people that are new to JavaScript, mainly using node.js.

It's important to note at this time that I don't think there is any programming language that is easier for people to learn than JavaScript. I've had to teach people Python. Teaching someone Python lasts for years. There is a huge amount of additional syntax and semantics that you don't learn until you're usually years in to programming Python. It's terrible for not just beginners but novice and intermediate programmers to work with "experts".

My main concern with some of the proposals is that I feel they add features and clever syntax for experts at the expense of keeping the language easy to understand for new programmers.

This is not that case for all the proposals. From what I've seen of the restructuring proposal it's actually quite nice and and obvious to read syntax for someone trying to reason about what it does. Contrast that with the current practice of new users reading 10 lines of code for handling default values and an Array.prototype.slice.call(arguments) WTF line of code at the top. It's a step in the right direction.

There are things we can do to make JavaScript a better and more easy to understand language. I think some of the proposals do exactly that.

But, some of them simply double the semantics and syntax in the language without a path to deprecate previous syntax. I'm a big fan of let, but if you don't deprecate var we're going to have to contend with new programmers keeping two sets of scoping rules in their head.

Finally, the features that are being added for "experts".

Generators.... so a function is sometimes a constructor, sometimes a function, and sometimes it's a generator?!?! Explain that in one paragraph that new programmers can understand, I dare you.

Array comprehensions.... very clever syntax that even experienced programmers can sometimes barely figure out. I dealt with these in Python all over the place, I wrote them as often as I could cause I wanted to be clever, and nobody understood what the hell my code was doing and I'm sorry for that.

To summarize, I don't think "new syntax === bad" is how we should characterize opposition to doubling the semantics and syntax in the language. Some of the proposals go a long way to removing confusion in the language while others are just far too clever to be understood easily by new developers.

Brendan said something very interesting in his talk at JSConf.eu, he said that because of the way TC39 works any new proposal that doesn't have (and I hope I'm paraphrasing this right) "sexy syntax to start with doesn't have much of a chance". I find that very enlightening. Too often in a group of people who design languages for a living sexy syntax is clever syntax.

Exactly what excites those who are professional language designers can be detrimental to this language's continuing success among new programmers, something it has for the last 10 years continued to outpace all the other languages you are not taking as inspiration.

# Mikeal Rogers (14 years ago)

s/restructuring/destructuring

# John J Barton (14 years ago)

+1

# Mikeal Rogers (14 years ago)

s/"not taking as inspiration"/"now taking as inspiration"

sorry for the typos, it's been a long hot day on this side of the world.

# Bob Nystrom (14 years ago)

On Tue, Oct 4, 2011 at 10:52 AM, Mikeal Rogers <mikeal.rogers at gmail.com>wrote:

My main concern with some of the proposals is that I feel they add

features and clever syntax for experts at the expense of keeping the language easy to understand for new programmers.

It's hard to satisfy both sets of users here. It's important to try and do our best, but many things are trade-offs. I don't think we can declare "thou shalt not change the language in a way that makes it harder for new users". If we can make things much better for working Javascripters at a small expense to newcomers, that may be a worthwhile trade-off or it may not. We should be open to making wise decisions like that, while remaining sympathetic to everyone who is writing JS.

I'm a big fan of let, but if you don't deprecate var we're going to have to

contend with new programmers keeping two sets of scoping rules in their head.

I would love to kill var. With fire.

Generators.... so a function is sometimes a constructor, sometimes a

function, and sometimes it's a generator?!?! Explain that in one paragraph that new programmers can understand, I dare you.

Because I can never refuse a dare...

A constructor is different from a regular function. Instead of returning the value that the body of the function returns, it returns a special newly-created object. Likewise, a generator is a special function that doesn't return what the body returns. Instead, it returns an object that lets you interrupt and resume that function. This object exposes a next()method. When you call that, the function runs until it hits a yield. When it does, the function is paused at that point, and the result of the yield is returned from next(). The next time you call next() it picks up from there and continues.

Brendan said something very interesting in his talk at JSConf.eu, he said

that because of the way TC39 works any new proposal that doesn't have (and I hope I'm paraphrasing this right) "sexy syntax to start with doesn't have much of a chance".

Brendan knows better than I, but often I feel that we have the opposite problem. If all you're proposing is syntax, it's easy for anyone to shoot it down by saying "You can already do that now." There's a fundmental difference between utility (can we do it all, ever, regardless of how many fingers we lose in the process) and usability (is it discoverable, easy, clear, pleasurable and not error-prone).

Because we're programmers we have a tendency to ignore usability concerns because they take more work to demonstrate. We like nice clear boolean switches: "I couldn't do this and now I can!" It's less satisfying for many of us to say "Now people encounter 17% fewer errors when doing this!"

Personally, I don't think that's the right way to look at things. Arguing from that angle pretty quickly turns into a Turing tarpit. I believe the entire reason we create languages is for usability. I think syntax does matter, because syntax is the user interface of the semantics. I rarely have complaints about JavaScript's semantics (except for var) but I find its notation awkward in some places. Improving those would make me more productive and make JS more fun for me to use.

# John J Barton (14 years ago)

On Tue, Oct 4, 2011 at 12:59 PM, Bob Nystrom <rnystrom at google.com> wrote:

A constructor is different from a regular function. Instead of returning the value that the body of the function returns, it returns a special newly-created object.

Sorry, already you lost me ;-) I guess you mean the operand of "new"? If so, then the different thing is the operator 'new'. It's "new" that makes the operand a constructor.

Likewise, a generator is a special function that doesn't return what the body returns.

But it does not look special. There is nothing similar to 'new' involved in the invocation of the generator.

Instead, it returns an object that lets you interrupt and resume that function. This object exposes a next() method. When you call that, the function runs until it hits a yield. When it does, the function is paused at that point, and the result of the yield is returned from next(). The next time you call next() it picks up from there and continues.

and the state of the generator is hidden from the developer as far as I can tell.

I think generators are an excellent example of a feature that is well prototyped (in FF JS 1.7+). I think the developer uptake is minimal, outside of the original advocates. I don't hear any clamor for other browsers to implement this feature. If generators never go further, that is an awesome outcome and we owe Dave Herman and other proponents of generators a lot of thanks for their efforts. Either way, "class" deserves at least as much investigation.

jjb

# Bob Nystrom (14 years ago)

On Tue, Oct 4, 2011 at 2:12 PM, John J Barton <johnjbarton at johnjbarton.com>wrote:

On Tue, Oct 4, 2011 at 12:59 PM, Bob Nystrom <rnystrom at google.com> wrote:

A constructor is different from a regular function. Instead of returning the value that the body of the function returns, it returns a special newly-created object.

Sorry, already you lost me ;-) I guess you mean the operand of "new"? If so, then the different thing is the operator 'new'. It's "new" that makes the operand a constructor.

It's the yield that makes a function a generator. One is visible at the callsite (which means you can forget it at the callsite), the other is visible at the definition.

Likewise, a generator is a special function that doesn't return what the body returns.

But it does not look special. There is nothing similar to 'new' involved in the invocation of the generator.

That's good because it means whether or not a function returns an iterable object by using yield or through some other means is an implementation detail of the function and doesn't bleed into every callsite. Let's say generators did have a callsite difference. Now imagine:

function countdown() { for (let i = 10; i >= 1; i--) yield i; }

let counter = generate countdown(); // <-- in callsite for (let i of counter) alert(i); alert('boom!');

This magic generate keyword means the function is to be treated like a generator. But then later it turns out that -- is really slow and you want to change countdown to:

function countdown() { return [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; }

Well, you can't. You'd have to fix each callsite too. Your abstraction has leaked. So I think generators do the right thing here. (And, conversely, I kind of think constructors do the wrong thing.)

and the state of the generator is hidden from the developer as far as I can

tell.

That's correct. That's often the cost of concision. By analogy: you can do a lot of stuff using either an explicit stack data structure or recursion. Using recursion is often more concise but then the state is hidden from you in the callstack. Sometimes that's a good trade-off, sometimes it's not.

I think generators are an excellent example of a feature that is well prototyped (in FF JS 1.7+). I think the developer uptake is minimal, outside of the original advocates. I don't hear any clamor for other browsers to implement this feature.

Browsers don't clamor, users do. If it was up to the browsers, they wouldn't implement anything. Implementing is hard work!

In languages that do have yield (Python, C#, and Lua are the ones I know) it's used pretty frequently and without complaint.

Either way, "class" deserves at least as much investigation.

Agreed!

# David Bruant (14 years ago)

Le 04/10/2011 18:51, Mike Samuel a écrit :

2011/10/4 David Bruant <david.bruant at labri.fr>:

Le 03/10/2011 22:49, Andrea Giammarchi a écrit :

Dear All, while I had the opportunity to ask directly to Brendan Eich this question, I would like to ask you 5 minutes of your precious time to understand common concerns from the JS community, summarized under my point of view in this post:

webreflection.blogspot.com/2011/10/dear-brendan-here-was-my-question.html

I would like to thank you in advance for your time and all possible answers/considerations/questions you may come up with. I have seen the sentence "I got 99 problems and JavaScript syntax ain't one" on twitter (by @mikeal), reused in Brendan's slide of CapitolJS and at JSConf.eu. Plenty of people seem to agree with this and I would like to take one minute to justify why syntax is important in my opinion.

Currently, I can cite only one IDE that has decent JavaScript support: WebStorm. And they have a very good completion suggestion engine. I have seen JavaScript IDEs stopping to analyse when coming across the (function(){...})(); pattern.

Why aren't there that many good JavaScript IDEs? Because JavaScript is ridiculously hard to analyse. It is weakly typed, and highly dynamic. For the last months, I have given myself the challenge to come up with a program which analyse jQuery and is able to retrieve the API. This is really hard. Most of the API is added with calls to jQuery.extend. Basically, a program would have to understand the semantics of jQuery.extend. But also understand that the output of $('a') has such prototype object with such properties. This is doable (since the WebStorm people do it), but very hard. No it doesn't.

Just walk the object graph starting from the root object and let the set of all reachable symbols be A. Load jQuery Walk the object graph again letting the set of all reachable symbols be B.

The public API of jQuery is then (B - A).

I wish things were that simple.


var a = function(){ var c = function(){}; c.prototype = {/put functions in here/};

return new c(); }

a is part of your API, but all functions of c.prototype could be considered as so as well (very close from the $('a').text function on jQuery objects for instance, but jQuery is fine since $('a').text can be found on jQuery.prototype) and you won't be able to figure it out unless you call the function or are able to analyse the function body which is what makes the analysis hard.

Good try though ;-)

For that matter, the best definition of an API in JavaScript I have come up with is:

  1. The set of properties added to the global object after running the script
  2. The set of properties added to the objects accessible from the global object (often refered as "extending built-ins")
  3. If one of the above is an object, its properties (own or inherited through a prototype) are also considered part of the API.
  4. If one of the above is a function and this function generates an object, properties of this object are also part of the API.
  5. Rules 3 and 4 are applied mutually recursively until reaching a fix point.

And I'm not 100% satisfied with it yet. Ideas of improvement welcomed.

# Dean Landolt (14 years ago)

On Tue, Oct 4, 2011 at 5:12 PM, John J Barton <johnjbarton at johnjbarton.com>wrote:

On Tue, Oct 4, 2011 at 12:59 PM, Bob Nystrom <rnystrom at google.com> wrote:

A constructor is different from a regular function. Instead of returning the value that the body of the function returns, it returns a special newly-created object.

Sorry, already you lost me ;-) I guess you mean the operand of "new"? If so, then the different thing is the operator 'new'. It's "new" that makes the operand a constructor.

Likewise, a generator is a special function that doesn't return what the body returns.

But it does not look special. There is nothing similar to 'new' involved in the invocation of the generator.

Instead, it returns an object that lets you interrupt and resume that function. This object exposes a next() method. When you call that, the function runs until it hits a yield. When it does, the function is paused at that point, and the result of the yield is returned from next(). The next time you call next() it picks up from there and continues.

and the state of the generator is hidden from the developer as far as I can tell.

I think generators are an excellent example of a feature that is well prototyped (in FF JS 1.7+). I think the developer uptake is minimal, outside of the original advocates.

Of course uptake is minimal -- it's only in one engine, and even then it doesn't yet match the spec.

# Dean Landolt (14 years ago)

On Tue, Oct 4, 2011 at 10:36 PM, Dean Landolt <dean at deanlandolt.com> wrote:

On Tue, Oct 4, 2011 at 5:12 PM, John J Barton <johnjbarton at johnjbarton.com

wrote:

On Tue, Oct 4, 2011 at 12:59 PM, Bob Nystrom <rnystrom at google.com> wrote:

A constructor is different from a regular function. Instead of returning the value that the body of the function returns, it returns a special newly-created object.

Sorry, already you lost me ;-) I guess you mean the operand of "new"? If so, then the different thing is the operator 'new'. It's "new" that makes the operand a constructor.

Likewise, a generator is a special function that doesn't return what the body returns.

But it does not look special. There is nothing similar to 'new' involved in the invocation of the generator.

Instead, it returns an object that lets you interrupt and resume that function. This object exposes a next() method. When you call that, the function runs until it hits a yield. When it does, the function is paused at that point, and the result of the yield is returned from next(). The next time you call next() it picks up from there and continues.

and the state of the generator is hidden from the developer as far as I can tell.

I think generators are an excellent example of a feature that is well prototyped (in FF JS 1.7+). I think the developer uptake is minimal, outside of the original advocates.

Of course uptake is minimal -- it's only in one engine, and even then it doesn't yet match the spec.

Err -- whoops, almost forgot about rhino. But my point still stands.

# Lasse Reichstein (14 years ago)

On Tue, Oct 4, 2011 at 6:19 PM, David Bruant <david.bruant at labri.fr> wrote:

** I sent a message here explaining the necessity of a syntax construct for a reliable bind [1]. There is a need to investingate (one reply was very close from a solution) to make sure that such a thing is not possible in pure ES5 (without making Function.prototype.bind non-configurable), but that would be one such thing that no language compiling to JavaScript could emulate (since impossible in the language itself).

I don't think "security" from malicious changes to Function.prototype.bind is a good argument for adding new operator syntax.

The problem doesn't stop with Function.prototype.bind. ES5 as a compilation target is built on a quagmire since almost all fundamental language operations are methods that can be changed. The operators are the exception, since you can't override their meaning[1], and I can see why you wish to introduce modification-safe operators for the operations you want to preserve - but why is Function.prototype.bind more important than, say, Math.pow? In the wrong hands, I'm sure you can subvert an encryption algorithm with a malicious Math.pow. We can't have operators for all functions, and you can't check every function before using it (and it wouldn't help if you could).

Also, with proxies and getters/setters, even operators aren't guaranteed to be safe unless they are defined extremely carefully. It used to be that property access (o.foo) was a safe way to look up a property on an object. Now it might trigger a proxy or accessor instead. This has actually diluted the safety of operators. Will new operators that seem safe now be diluted the same way in the future?

With ES5 getters and (inherited!) setters, you can install a "javascript rootkit" that modifies some of the builtins, perhaps put some selected getters/setters on Object.prototype, and hides every trace of it from other scripts. To prevent that kind of maliciousness, you need to go the way of SES and lock down the entire environment before any untrusted code is touched, and in that case Function.prototype.bind is just as safe as an operator.

(On the other hand, it's actually a fun experience to write Javascript code that can't be affected by a modified environment - the same way three-legged races are fun :)

Personally, I'd prefer all the built-in functions to be unconfigurable, so a language user would actually know what function they are calling ahead of time.

/L 'Freeze them! Freeze them all!'

[1] But the operators can potentially do type coercion that allows arbitrary side-effects at unexpected times.

# David Bruant (14 years ago)

Le 05/10/2011 10:17, Lasse Reichstein a écrit :

On Tue, Oct 4, 2011 at 6:19 PM, David Bruant <david.bruant at labri.fr <mailto:david.bruant at labri.fr>> wrote:

I sent a message here explaining the necessity of a syntax
construct for a reliable bind [1]. There is a need to investingate
(one reply was very close from a solution) to make sure that such
a thing is not possible in pure ES5 (without making
Function.prototype.bind non-configurable), but that would be one
such thing that no language compiling to JavaScript could emulate
(since impossible in the language itself).

I don't think "security" from malicious changes to Function.prototype.bind is a good argument for adding new operator syntax.

The problem doesn't stop with Function.prototype.bind. ES5 as a compilation target is built on a quagmire since almost all fundamental language operations are methods that can be changed. The operators are the exception, since you can't override their meaning[1], and I can see why you wish to introduce modification-safe operators for the operations you want to preserve - but why is Function.prototype.bind more important than, say, Math.pow?

The difference I saw is that you can keep a reference to Math.pow within a scope of yours and you'll be fine. Such a thing doesn't seem possible with call, apply and bind, mostly because you need to rely on at least one of them in order to do call.call or call.bind, etc. and consequently, you always depend on the value on Function.prototype.* in a way or another.

As i said before, there is a reliable way to do a call which is f(), but you can't choose the value of |this|. That's what originally motivated the idea of a syntax-based bind.

I don't think that the other functions require such a thing.

# Mark S. Miller (14 years ago)

Since you're assuming you can initialize and grab stuff before your context is corrupted, what's wrong with Lasse's earlier (and very clever!)

var call = Function.prototype.call.bind(Function.prototype.call);

and by direct analogy:

var apply = Function.prototype.call.bind(Function.prototype.apply);
var bind = Function.prototype.call.bind(Function.prototype.bind);

?

If there's a vulnerability with this technique, I need to know that asap, as I'm about to start writing code that depends on it for security. So any vulnerabilities you or anyone can point out now will be greatly appreciated. Thanks.

# David Bruant (14 years ago)

Le 05/10/2011 10:33, Mark S. Miller a écrit :

Since you're assuming you can initialize and grab stuff before your context is corrupted, what's wrong with Lasse's earlier (and very clever!)

var call = Function.prototype.call.bind(Function.prototype.call);

and by direct analogy:

var apply = Function.prototype.call.bind(Function.prototype.apply);
var bind = Function.prototype.call.bind(Function.prototype.bind);

?

Nothing's wrong. I forgot about this, sorry. It is indeed very clever. I take back what I said about the necessity of a syntax construct for bind.

# Andrea Giammarchi (14 years ago)

dunno how we ended up here but I would rather use this approach in a private scope:

var // used to trap function calls via bind invoke = Function.call, // normal use cases bind = invoke.bind(invoke.bind), apply = bind(invoke, invoke.apply), call = bind(invoke, invoke) ;

var hasOwnProperty = bind(invoke, {}.hasOwnProperty);

hasOwnProperty({key:1}, "key"); // true call([].slice, [1,2,3], 1); // 2,3 apply([].slice, [1,2,3], [1]); // 2,3

, Andrea Giammarchi

# Mark S. Miller (14 years ago)

That's very nice, thanks.

# John J Barton (14 years ago)

On Tue, Oct 4, 2011 at 2:33 PM, Bob Nystrom <rnystrom at google.com> wrote:

On Tue, Oct 4, 2011 at 2:12 PM, John J Barton <johnjbarton at johnjbarton.com

wrote:

On Tue, Oct 4, 2011 at 12:59 PM, Bob Nystrom <rnystrom at google.com> wrote:

A constructor is different from a regular function. Instead of returning the value that the body of the function returns, it returns a special newly-created object.

Sorry, already you lost me ;-) I guess you mean the operand of "new"? If so, then the different thing is the operator 'new'. It's "new" that makes the operand a constructor.

It's the yield that makes a function a generator. One is visible at the callsite (which means you can forget it at the callsite), the other is visible at the definition.

Likewise, a generator is a special function that doesn't return what the body returns.

But it does not look special. There is nothing similar to 'new' involved in the invocation of the generator.

That's good because it means whether or not a function returns an iterable object by using yield or through some other means is an implementation detail of the function and doesn't bleed into every callsite. Let's say generators did have a callsite difference. Now imagine:

function countdown() { for (let i = 10; i >= 1; i--) yield i; }

let counter = generate countdown(); // <-- in callsite for (let i of counter) alert(i); alert('boom!');

This magic generate keyword means the function is to be treated like a generator. But then later it turns out that -- is really slow and you want to change countdown to:

function countdown() { return [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; }

Well, you can't. You'd have to fix each callsite too. Your abstraction has leaked. So I think generators do the right thing here. (And, conversely, I kind of think constructors do the wrong thing.)

We can agree that |new| is a mess even if we don't agree on generators.

and the state of the generator is hidden from the developer as far as I can

tell.

That's correct. That's often the cost of concision. By analogy: you can do a lot of stuff using either an explicit stack data structure or recursion. Using recursion is often more concise but then the state is hidden from you in the callstack. Sometimes that's a good trade-off, sometimes it's not.

Thanks, that analogy helps confirm my opinion of generators. In my experience, the good trade-off is recursion on data structures and the not-good-trade-off is recursion for iteration. So far the only examples I've seen for generators involve iteration.

I think generators are an excellent example of a feature that is well prototyped (in FF JS 1.7+). I think the developer uptake is minimal, outside of the original advocates. I don't hear any clamor for other browsers to implement this feature.

Browsers don't clamor, users do. If it was up to the browsers, they wouldn't implement anything. Implementing is hard work!

I've heard no clamor at all. Really this is a niche feature, an aid for the rare case where conventional iterators are a poor match.

jjb

# Dean Landolt (14 years ago)

On Wed, Oct 5, 2011 at 10:18 AM, John J Barton <johnjbarton at johnjbarton.com>wrote:

On Tue, Oct 4, 2011 at 2:33 PM, Bob Nystrom <rnystrom at google.com> wrote:

On Tue, Oct 4, 2011 at 2:12 PM, John J Barton < johnjbarton at johnjbarton.com> wrote:

On Tue, Oct 4, 2011 at 12:59 PM, Bob Nystrom <rnystrom at google.com>wrote:

A constructor is different from a regular function. Instead of returning the value that the body of the function returns, it returns a special newly-created object.

Sorry, already you lost me ;-) I guess you mean the operand of "new"? If so, then the different thing is the operator 'new'. It's "new" that makes the operand a constructor.

It's the yield that makes a function a generator. One is visible at the callsite (which means you can forget it at the callsite), the other is visible at the definition.

Likewise, a generator is a special function that doesn't return what the body returns.

But it does not look special. There is nothing similar to 'new' involved in the invocation of the generator.

That's good because it means whether or not a function returns an iterable object by using yield or through some other means is an implementation detail of the function and doesn't bleed into every callsite. Let's say generators did have a callsite difference. Now imagine:

function countdown() { for (let i = 10; i >= 1; i--) yield i; }

let counter = generate countdown(); // <-- in callsite for (let i of counter) alert(i); alert('boom!');

This magic generate keyword means the function is to be treated like a generator. But then later it turns out that -- is really slow and you want to change countdown to:

function countdown() { return [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; }

Well, you can't. You'd have to fix each callsite too. Your abstraction has leaked. So I think generators do the right thing here. (And, conversely, I kind of think constructors do the wrong thing.)

We can agree that |new| is a mess even if we don't agree on generators.

and the state of the generator is hidden from the developer as far as I

can tell.

That's correct. That's often the cost of concision. By analogy: you can do a lot of stuff using either an explicit stack data structure or recursion. Using recursion is often more concise but then the state is hidden from you in the callstack. Sometimes that's a good trade-off, sometimes it's not.

Thanks, that analogy helps confirm my opinion of generators. In my experience, the good trade-off is recursion on data structures and the not-good-trade-off is recursion for iteration. So far the only examples I've seen for generators involve iteration.

I think generators are an excellent example of a feature that is well prototyped (in FF JS 1.7+). I think the developer uptake is minimal, outside of the original advocates. I don't hear any clamor for other browsers to implement this feature.

Browsers don't clamor, users do. If it was up to the browsers, they wouldn't implement anything. Implementing is hard work!

I've heard no clamor at all. Really this is a niche feature, an aid for the rare case where conventional iterators are a poor match.

Generators are more than iteration optimizations -- they enable shallow frame continuations, and open the doors to some really nice async programming patterns (just the beginnings of which are demonstrated by Dave Herman's task.js [1]).

Again, they're not fully implemented in any engine, so library support is practically non-existent. How are users supposed to clamor for a feature that can't demonstrate itself as advantageous? I've heard plenty of calls for language-level async support -- generators enable this without the well-documented hazards of the alternatives.

[1] dherman/taskjs

# Bob Nystrom (14 years ago)

On Wed, Oct 5, 2011 at 7:18 AM, John J Barton <johnjbarton at johnjbarton.com>wrote:

On Tue, Oct 4, 2011 at 2:33 PM, Bob Nystrom <rnystrom at google.com> wrote:

That's correct. That's often the cost of concision. By analogy: you can do a lot of stuff using either an explicit stack data structure or recursion. Using recursion is often more concise but then the state is hidden from you in the callstack. Sometimes that's a good trade-off, sometimes it's not.

Thanks, that analogy helps confirm my opinion of generators. In my experience, the good trade-off is recursion on data structures and the not-good-trade-off is recursion for iteration.

Yes, I wasn't making any claim about using recursion for iteration. Maybe I need to be more concrete here:

If you need to walk a tree, you can do so using recursion or you can use an explicit stack data structure. The former is usually more terse (because it implicitly relies on the callstack itself storing the stack) but the other can be more clear.

By analogy, if you need to produce a sequence of values, you can do so using generators, or you can use an explicit iterator object. Again, the former is usually more terse (because the language automatically creates the iterator object for you given a function containing yield) but the latter can be more clear (because the state is laid bare).

Note that those two paragraphs are separate. I'm not talking about using recursion for iteration. Is this clearer now?

So far the only examples I've seen for generators involve iteration.

Yup, that's what generators do. And recursion involves stacks.

I've heard no clamor at all.

That may be true, but it may say as much about your surrounding auditory environment as it does the feature in question. You may be right, but simply saying "Bigfoot isn't in my living room" doesn't disprove the existence of Bigfoot.

There are languages in wide use that have this feature. None of those languages (Lua, C#, Python) has a reputation for catering to the esoteric programming language fanbase.

Really this is a niche feature, an aid for the rare case where conventional

iterators are a poor match.

They said the same thing about closures. I agree that generators aren't the most important language feature in the world, but I think if you had them you'd find that you used them.

Here's an example:

let tree = [['a', 'b', 'c'], [['d', 'e'], 'f'], ['g']];

let inOrder = walk(tree); for (node of walk(tree)) alert(node); // a, b, c, d, ...

walk(tree) { if (typeof tree == 'string') { yield tree; // leaf } else { yield* walk(tree); // branch } }

What would the above look like without generators?

# Quildreen Motta (14 years ago)

On 05/10/11 22:05, Brendan Eich wrote:

On Oct 4, 2011, at 7:19 AM, Juan Ignacio Dopazo wrote:

Yes, tools should be better, but they need to start becoming better by themselves as previous discussions here have noted.

However, there are problems in the language that need to be addressed by both syntax and APIs. We need:

  • A sane way of dealing with equality, identity and basically a lot of what's in wtfjs.com

Some of that is due to implicit conversions, not any equality-ish operator.

I really never understood people's complaints about equality comparisons in JavaScript. There are only two operators, with clear and well defined semantics/use-cases:

`==' (Abstract equality) is used for comparing the value of two objects, without taking data-structure into account.

`===' (Strict equality) is used for comparing the value of two objects, taking data-structure into account.

Could someone enlighten me on what is not intuitive or "sane" about that? I mean, my starting point for comparing equality operator sanity is Common Lisp's with its 10+ equality predicates — some being implementation-dependant, so YMMV.

# Brendan Eich (14 years ago)

On Oct 5, 2011, at 7:01 PM, Quildreen Motta wrote:

On 05/10/11 22:05, Brendan Eich wrote:

On Oct 4, 2011, at 7:19 AM, Juan Ignacio Dopazo wrote:

Yes, tools should be better, but they need to start becoming better by themselves as previous discussions here have noted.

However, there are problems in the language that need to be addressed by both syntax and APIs. We need:

  • A sane way of dealing with equality, identity and basically a lot of what's in wtfjs.com

Some of that is due to implicit conversions, not any equality-ish operator. I really never understood people's complaints about equality comparisons in JavaScript. There are only two operators, with clear and well defined semantics/use-cases:

`==' (Abstract equality) is used for comparing the value of two objects, without taking data-structure into account.

This operator is insane due to implicit conversions it does when operand types are not the same. In such cases it is not an equivalence relation.

`===' (Strict equality) is used for comparing the value of two objects, taking data-structure into account.

This operator is fine, unless you want to test (NaN is NaN) or (-0 isnt 0). There, you need is/isnt.

Could someone enlighten me on what is not intuitive or "sane" about that? I mean, my starting point for comparing equality operator sanity is Common Lisp's with its 10+ equality predicates — some being implementation-dependant, so YMMV.

Yes, during ES1 days Guy Steele said we were not worse than Common Lisp. Still doesn't excuse ==/!= in the case of operands of different types.

# Quildreen Motta (14 years ago)

On 05/10/11 23:06, Brendan Eich wrote:

On Oct 5, 2011, at 7:01 PM, Quildreen Motta wrote:

On 05/10/11 22:05, Brendan Eich wrote:

On Oct 4, 2011, at 7:19 AM, Juan Ignacio Dopazo wrote:

Yes, tools should be better, but they need to start becoming better by themselves as previous discussions here have noted.

However, there are problems in the language that need to be addressed by both syntax and APIs. We need:

  • A sane way of dealing with equality, identity and basically a lot of what's in wtfjs.com Some of that is due to implicit conversions, not any equality-ish operator. I really never understood people's complaints about equality comparisons in JavaScript. There are only two operators, with clear and well defined semantics/use-cases:

`==' (Abstract equality) is used for comparing the value of two objects, without taking data-structure into account. This operator is insane due to implicit conversions it does when operand types are not the same. In such cases it is not an equivalence relation.

I would argue this is not entirely true. It would depend on what you consider "equivalence". As I said, the way I see the abstract equality algorithm is that it compares "values" — by which I mean primitive values, — such that it can't really take into account the data structure of the operands.

So, 1' equals"1"' which equals [1]' which equals{toString:function() "1"}' which might equal just about any other object which toString' returns "1". In this case, the semantics are pretty sane (though some might argue about[1]' and other objects). We could say it would be analogous to having a book in several different medias — ebook, paper, audio, etc. Just because the medias are different, it doesn't mean the contents of the book are.

I have to agree, however, that some of the conversions are not as intuitive — at first glance — as the ones in the relational operators, which always convert the operands to the a numeric primitive value. Perhaps some of the fault of abstract equality's usage might be on the lack of chaining comparisons, though:


// This is not what you'd usually assume it to be, based on mathematical notation 2 == "2" == [2] // => false

// ...because operations are done this way (2 == "2") == [2] → (2 == ToNumber("2")) == [2] → (2 == 2) == [2] → true == [2] → true == ToPrimitive([2]) // [2].valueOf().toString() → ToNumber(true) == "2" → 1 == ToNumber("2") → 1 == 2 → false

That said, I don't consider the semantics of abstract equality that complex to consider it a problem — there are some recursive conversions, yes. ToPrimitive might get confusing depending on how toString and valueOf are defined in the object. That might be a problem or an interesting feature depending on the particular use-case, considering how dynamic JS is.

That's not to say it's perfect in every single conversion, but it gets at least 90% of all the practical use cases right. Other people probably have a different opinion on this kind of equivalence coming from a strong or static/strong typed background.

`===' (Strict equality) is used for comparing the value of two objects, taking data-structure into account. This operator is fine, unless you want to test (NaN is NaN) or (-0 isnt 0). There, you need is/isnt.

Is `egal' already in ES.next?

# Juan Ignacio Dopazo (14 years ago)

On Thu, Oct 6, 2011 at 12:01 AM, Quildreen Motta <quildreen at gmail.com>wrote:

On 05/10/11 23:06, Brendan Eich wrote:

On Oct 5, 2011, at 7:01 PM, Quildreen Motta wrote:

On 05/10/11 22:05, Brendan Eich wrote:

On Oct 4, 2011, at 7:19 AM, Juan Ignacio Dopazo wrote:

  • A sane way of dealing with equality, identity and basically a lot of

what's in wtfjs.com

Some of that is due to implicit conversions, not any equality-ish operator.

I really never understood people's complaints about equality comparisons in JavaScript. There are only two operators, with clear and well defined semantics/use-cases:

`==' (Abstract equality) is used for comparing the value of two objects, without taking data-structure into account.

This operator is insane due to implicit conversions it does when operand types are not the same. In such cases it is not an equivalence relation.

Yes, == and === work fine. The problem is not in how they work, but in the learning curve for new users of the language. I think most expect == to work as ===. That, combined with object wrappers for values (new Number(5), new Boolean(false), etc), seems to be an endless source of confusion for beginners.

Of course pretty much every operator does type coercion, so tampering with == and === could be as much detrimental as constructive.

Juan

# Brendan Eich (14 years ago)

On Oct 5, 2011, at 8:01 PM, Quildreen Motta wrote:

On 05/10/11 23:06, Brendan Eich wrote:

`==' (Abstract equality) is used for comparing the value of two objects, without taking data-structure into account. This operator is insane due to implicit conversions it does when operand types are not the same. In such cases it is not an equivalence relation. I would argue this is not entirely true. It would depend on what you consider "equivalence".

"Equivalence relation" is a well-defined technical phrase, and I was employing it intentionally. Please read

en.wikipedia.org/wiki/Equivalence_relation

and note the three required properties: an e.r. must be reflexive, symmetric, and transitive.

"" == 0 && 0 == "0" but "" != "0" in JS. If == were transitive, then "" would have to == "0".

(NaN != NaN violates "reflexive" but it's a special case for numerical analysts, I'm told -- other languages do likewise.)

This operator is fine, unless you want to test (NaN is NaN) or (-0 isnt 0). There, you need is/isnt. Is `egal' already in ES.next?

Already answered -- wiki.ecmascript.org/doku.php?id=harmony:egal. That link remains in harmony:proposals.

# Brendan Eich (14 years ago)

On Oct 4, 2011, at 10:52 AM, Mikeal Rogers wrote:

But, some of them simply double the semantics and syntax in the language without a path to deprecate previous syntax. I'm a big fan of let, but if you don't deprecate var we're going to have to contend with new programmers keeping two sets of scoping rules in their head.

You mean by deprecate what, exactly?

Web JS is full of var. Making any attempt to migrate a big hunk of it to ES6 require replacing all 'var' with 'let' is a huge tax, since scoping works differently.

Ok, how about saying if you use 'let' in a function or at top level, you can no longer use 'var'? That's less of a tax on average, but for a long program or single function, it's as bad.

On the web, deprecation is separate from obsolescence. You don't remove the bad old thing until the good new thing is out and about and actually in use. You might have to wait for the bad old thing to wither almost to nothing, all by itself.

Or sometimes a breaking change that actually improves semantics, rarely breaks valid content, and has better security can be shipped sooner. Examples include window name targeting and mixed http:/https: content not loading the http: content (IE9 does this, good on them).

'var' is not such a case.

Brendan said something very interesting in his talk at JSConf.eu, he said that because of the way TC39 works any new proposal that doesn't have (and I hope I'm paraphrasing this right) "sexy syntax to start with doesn't have much of a chance".

I never said that. In particular, I did not say "sexy", and I didn't say "start" -- here's proof. <| and .{ are proposed for ES6. They aren't quite right, many on the committee and in the community believe. That doesn't mean they'll fail to be included under some syntax -- the semantics are good (although .{ is just Object.extend, so the API would be good by itself).

What I said was that it's hard to agree on syntax unless the proposer nails it, really (no double entendre there!). Often by using syntax from a nearby language. Even then, .e.g. generators (we distinguish them at the head via function*) and block-lambdas, some who don't know or do not like the nearby language balk.

My main point was that syntax is hard. But syntax is UI and JS's UI has real usability bugs. I'm glad you find it easy to teach. That's not the only consideration though, because after people learn a language, as they keep using it they do progress to become fluent, even expert, at it, and its usability problems come to the fore.

# Brendan Eich (14 years ago)

A huge +1 and hugs and kisses for your entire post. And I didn't say anything like Mikeal's paraphrase, and the ES6 harmony:proposals bear this out (<| is unsexy in my current font!).

It's especially important not to discount shorthands and sugar for cliché, even though they could be replaced by equivalent long-hand. English does not only have "is not". It has "isn't" as well, and we're better off for that kind of contraction. Yes, this makes it harder to teach -- I know, I have a 7 and a 6 year old learning the rules right now, along with the raft of irregular verbs in English that such children need to know -- but learners manage.

# Brendan Eich (14 years ago)

On Oct 4, 2011, at 7:36 PM, Dean Landolt wrote:

I think generators are an excellent example of a feature that is well prototyped (in FF JS 1.7+). I think the developer uptake is minimal, outside of the original advocates.

Of course uptake is minimal -- it's only in one engine, and even then it doesn't yet match the spec.

Please get the historical order right. The spec changed only recently, the implementation matched the previous spec (of five years' standing).

Anyway, the changes are minor in the scheme of things, or in the terms of this debate. Unless the issue is the function head not looking different? Fixed that in ES6 for ya! ;-) function* also makes the empty basis case work for yield*.

# Claus Reinke (14 years ago)

You mean by deprecate what, exactly?

Web JS is full of var. Making any attempt to migrate a big hunk of it to ES6 require replacing all 'var' with 'let' is a huge tax, since scoping works differently.

Ok, how about saying if you use 'let' in a function or at top level, you can no longer use 'var'? That's less of a tax on average, but for a long program or single function, it's as bad.

On the web, deprecation is separate from obsolescence. You don't remove the bad old thing until the good new thing is out and about and actually in use. You might have to wait for the bad old thing to wither almost to nothing, all by itself.

Sometimes, I wish non-web languages would offer similar backwards compatibility, sometimes, I wish web languages were not burdened by backwards compatibility..

One way to help with this problem is automation: we already accept that compilers translating ES.next to ES.current can help with experimentation, design, and early adaptation wrt new features. In the same spirit, compilers from ES.legacy to ES.current could speed up deprecation of unwanted features.

This idea is a generalization of special-purpose refactoring tools that support API migration or schema evolution (as opposed to general-purpose code restructuring). One paper that expresses the idea in more detail is

Regrowing a Language
Refactoring Tools Allow Programming Languages to Evolve
Overbey, Johnson, OOPSLA 2009
http://jeff.over.bz/papers/2009/onward2009.pdf

Claus clausreinke.github.com

# Mikeal Rogers (14 years ago)

On Thu, Oct 6, 2011 at 5:08 AM, Brendan Eich <brendan at mozilla.com> wrote:

On Oct 4, 2011, at 10:52 AM, Mikeal Rogers wrote:

But, some of them simply double the semantics and syntax in the language without a path to deprecate previous syntax. I'm a big fan of let, but if you don't deprecate var we're going to have to contend with new programmers keeping two sets of scoping rules in their head.

You mean by deprecate what, exactly?

Web JS is full of var. Making any attempt to migrate a big hunk of it to ES6 require replacing all 'var' with 'let' is a huge tax, since scoping works differently.

Ok, how about saying if you use 'let' in a function or at top level, you can no longer use 'var'? That's less of a tax on average, but for a long program or single function, it's as bad.

This is exactly what I was getting at.

On the web, deprecation is separate from obsolescence. You don't remove the bad old thing until the good new thing is out and about and actually in use. You might have to wait for the bad old thing to wither almost to nothing, all by itself.

Or sometimes a breaking change that actually improves semantics, rarely breaks valid content, and has better security can be shipped sooner. Examples include window name targeting and mixed http:/https: content not loading the http: content (IE9 does this, good on them).

'var' is not such a case.

Brendan said something very interesting in his talk at JSConf.eu, he said that because of the way TC39 works any new proposal that doesn't have (and I hope I'm paraphrasing this right) "sexy syntax to start with doesn't have much of a chance".

I never said that. In particular, I did not say "sexy", and I didn't say "start" -- here's proof. <| and .{ are proposed for ES6. They aren't quite right, many on the committee and in the community believe. That doesn't mean they'll fail to be included under some syntax -- the semantics are good (although .{ is just Object.extend, so the API would be good by itself).

What I said was that it's hard to agree on syntax unless the proposer nails it, really (no double entendre there!). Often by using syntax from a nearby language. Even then, .e.g. generators (we distinguish them at the head via function*) and block-lambdas, some who don't know or do not like the nearby language balk.

My main point was that syntax is hard. But syntax is UI and JS's UI has real usability bugs. I'm glad you find it easy to teach. That's not the only consideration though, because after people learn a language, as they keep using it they do progress to become fluent, even expert, at it, and its usability problems come to the fore.

Semantics for experts is fine so long as the syntax doesn't confuse beginning to intermediate programmers. Like I said, I think the destructuring proposal is a great example of syntax that makes the semantics behind it obvious especially when compared to what it takes to accomplish the same task now.

I would contrast that with generators. With ES5's forEach, map and filter, which are quite simple and obvious, I wonder why the semantics of generators can't be achieved in a way that is clearer to less than expert programmers.

I also haven't touched classes yet. Just saying the word makes me cringe a little, but once i get over my initial emotional reaction I think about how difficult it is currently to juggle code that is using traditional prototypical inheritance and code that is using an entirely different pattern people use to hack class inheritance in today. Having just a syntax, even without any more semantics than people already add today, could reduce that confusion. I'm still on the fence about it because I'm so initially reactionary about the word itself... "class".....

# Russell Leggett (14 years ago)

On Oct 7, 2011, at 6:51 AM, Mikeal Rogers <mikeal.rogers at gmail.com> wrote:

On Thu, Oct 6, 2011 at 5:08 AM, Brendan Eich <brendan at mozilla.com> wrote: On Oct 4, 2011, at 10:52 AM, Mikeal Rogers wrote:

But, some of them simply double the semantics and syntax in the language without a path to deprecate previous syntax. I'm a big fan of let, but if you don't deprecate var we're going to have to contend with new programmers keeping two sets of scoping rules in their head.

You mean by deprecate what, exactly?

Web JS is full of var. Making any attempt to migrate a big hunk of it to ES6 require replacing all 'var' with 'let' is a huge tax, since scoping works differently.

Ok, how about saying if you use 'let' in a function or at top level, you can no longer use 'var'? That's less of a tax on average, but for a long program or single function, it's as bad.

This is exactly what I was getting at.

Clearly this could just be solved with tooling. The first time your editor sees the let keyword in a file, an animated image of Douglas Crockford's head would appear with the message, "It looks like you're trying to use block scope."

Sorry, I couldn't resist.

# Dean Landolt (14 years ago)

This reply's a little late -- just catching up on old threads...

On Thu, Oct 6, 2011 at 12:21 AM, Brendan Eich <brendan at mozilla.com> wrote:

On Oct 4, 2011, at 7:36 PM, Dean Landolt wrote:

I think generators are an excellent example of a feature that is well

prototyped (in FF JS 1.7+). I think the developer uptake is minimal, outside of the original advocates.

Of course uptake is minimal -- it's only in one engine, and even then it doesn't yet match the spec.

Please get the historical order right. The spec changed only recently, the implementation matched the previous spec (of five years' standing).

Apologies -- I didn't even realize there was an old spec :)

Anyway, the changes are minor in the scheme of things, or in the terms of

this debate. Unless the issue is the function head not looking different? Fixed that in ES6 for ya! ;-) function* also makes the empty basis case work for yield*.

I'm aware, and I'm very happy about that. Perhaps the point I was trying to make wasn't clear -- I was trying to demonstrate why this statement was begging the question:

I've heard no clamor at all. Really this is a niche feature, an aid for the

rare case where conventional iterators are a poor match.

Generators as single-frame-continuations require library support. Library support requires generator implementations. Regardless of mozilla's intentions, the lack of a broader implementation base makes this demand for "clamor" really unlikely.

# Dean Landolt (14 years ago)

On Wed, Oct 5, 2011 at 1:40 PM, Bob Nystrom <rnystrom at google.com> wrote:

On Wed, Oct 5, 2011 at 7:18 AM, John J Barton <johnjbarton at johnjbarton.com

wrote:

On Tue, Oct 4, 2011 at 2:33 PM, Bob Nystrom <rnystrom at google.com> wrote:

That's correct. That's often the cost of concision. By analogy: you can do a lot of stuff using either an explicit stack data structure or recursion. Using recursion is often more concise but then the state is hidden from you in the callstack. Sometimes that's a good trade-off, sometimes it's not.

Thanks, that analogy helps confirm my opinion of generators. In my experience, the good trade-off is recursion on data structures and the not-good-trade-off is recursion for iteration.

Yes, I wasn't making any claim about using recursion for iteration. Maybe I need to be more concrete here:

If you need to walk a tree, you can do so using recursion or you can use an explicit stack data structure. The former is usually more terse (because it implicitly relies on the callstack itself storing the stack) but the other can be more clear.

By analogy, if you need to produce a sequence of values, you can do so using generators, or you can use an explicit iterator object. Again, the former is usually more terse (because the language automatically creates the iterator object for you given a function containing yield) but the latter can be more clear (because the state is laid bare).

Note that those two paragraphs are separate. I'm not talking about using recursion for iteration. Is this clearer now?

So far the only examples I've seen for generators involve iteration.

Yup, that's what generators do. And recursion involves stacks.

I've heard no clamor at all.

That may be true, but it may say as much about your surrounding auditory environment as it does the feature in question. You may be right, but simply saying "Bigfoot isn't in my living room" doesn't disprove the existence of Bigfoot.

There are languages in wide use that have this feature. None of those languages (Lua, C#, Python) has a reputation for catering to the esoteric programming language fanbase.

Really this is a niche feature, an aid for the rare case where

conventional iterators are a poor match.

They said the same thing about closures. I agree that generators aren't the most important language feature in the world, but I think if you had them you'd find that you used them.

Here's an example:

let tree = [['a', 'b', 'c'], [['d', 'e'], 'f'], ['g']];

let inOrder = walk(tree); for (node of walk(tree)) alert(node); // a, b, c, d, ...

walk(tree) { if (typeof tree == 'string') { yield tree; // leaf } else { yield* walk(tree); // branch } }

What would the above look like without generators?

Woah there -- where does this syntax come from? Was walk(tree) {...} supposed to be function* walk(tree) {...} instead? Or is this intended to represent some sort of method generator? If the latter, doesn't this need some mechanism to distinguish it from a non-generator method?

Has there been any discussion of a generator method syntax in the class discussions?

# Bob Nystrom (14 years ago)

On Mon, Oct 10, 2011 at 1:33 PM, Dean Landolt <dean at deanlandolt.com> wrote:

On Wed, Oct 5, 2011 at 1:40 PM, Bob Nystrom <rnystrom at google.com> wrote:

On Wed, Oct 5, 2011 at 7:18 AM, John J Barton < johnjbarton at johnjbarton.com> wrote:

On Tue, Oct 4, 2011 at 2:33 PM, Bob Nystrom <rnystrom at google.com> wrote:

That's correct. That's often the cost of concision. By analogy: you can do a lot of stuff using either an explicit stack data structure or recursion. Using recursion is often more concise but then the state is hidden from you in the callstack. Sometimes that's a good trade-off, sometimes it's not.

Thanks, that analogy helps confirm my opinion of generators. In my experience, the good trade-off is recursion on data structures and the not-good-trade-off is recursion for iteration.

Yes, I wasn't making any claim about using recursion for iteration. Maybe I need to be more concrete here:

If you need to walk a tree, you can do so using recursion or you can use an explicit stack data structure. The former is usually more terse (because it implicitly relies on the callstack itself storing the stack) but the other can be more clear.

By analogy, if you need to produce a sequence of values, you can do so using generators, or you can use an explicit iterator object. Again, the former is usually more terse (because the language automatically creates the iterator object for you given a function containing yield) but the latter can be more clear (because the state is laid bare).

Note that those two paragraphs are separate. I'm not talking about using recursion for iteration. Is this clearer now?

So far the only examples I've seen for generators involve iteration.

Yup, that's what generators do. And recursion involves stacks.

I've heard no clamor at all.

That may be true, but it may say as much about your surrounding auditory environment as it does the feature in question. You may be right, but simply saying "Bigfoot isn't in my living room" doesn't disprove the existence of Bigfoot.

There are languages in wide use that have this feature. None of those languages (Lua, C#, Python) has a reputation for catering to the esoteric programming language fanbase.

Really this is a niche feature, an aid for the rare case where

conventional iterators are a poor match.

They said the same thing about closures. I agree that generators aren't the most important language feature in the world, but I think if you had them you'd find that you used them.

Here's an example:

let tree = [['a', 'b', 'c'], [['d', 'e'], 'f'], ['g']];

let inOrder = walk(tree); for (node of walk(tree)) alert(node); // a, b, c, d, ...

walk(tree) { if (typeof tree == 'string') { yield tree; // leaf } else { yield* walk(tree); // branch } }

What would the above look like without generators?

Woah there -- where does this syntax come from? Was walk(tree) {...} supposed to be function* walk(tree) {...} instead? Or is this intended to represent some sort of method generator? If the latter, doesn't this need some mechanism to distinguish it from a non-generator method?

Whoops, my mistake. Too much time working on the class proposal where "function" isn't needed for methods. Yes, that should be function*.

# Brendan Eich (14 years ago)

On Oct 10, 2011, at 1:27 PM, Dean Landolt wrote:

I'm aware, and I'm very happy about that. Perhaps the point I was trying to make wasn't clear -- I was trying to demonstrate why this statement was begging the question:

I've heard no clamor at all. Really this is a niche feature, an aid for the rare case where conventional iterators are a poor match.

Generators as single-frame-continuations require library support. Library support requires generator implementations. Regardless of mozilla's intentions, the lack of a broader implementation base makes this demand for "clamor" really unlikely.

Right, agreed. You won't have any user focus group tell you what they don't know they're missing. Steve Jobs said that (half-kidding).

# Brendan Eich (14 years ago)

On Oct 10, 2011, at 1:41 PM, Bob Nystrom wrote:

On Mon, Oct 10, 2011 at 1:33 PM, Dean Landolt <dean at deanlandolt.com> wrote:

Here's an example:

let tree = [['a', 'b', 'c'], [['d', 'e'], 'f'], ['g']];

let inOrder = walk(tree); for (node of walk(tree)) alert(node); // a, b, c, d, ...

walk(tree) { if (typeof tree == 'string') { yield tree; // leaf } else { yield* walk(tree); // branch } }

What would the above look like without generators?

Woah there -- where does this syntax come from? Was walk(tree) {...} supposed to be function* walk(tree) {...} instead? Or is this intended to represent some sort of method generator? If the latter, doesn't this need some mechanism to distinguish it from a non-generator method?

Whoops, my mistake. Too much time working on the class proposal where "function" isn't needed for methods.

I spy a Dart ;-).

Yes, that should be function*.

Still a great delegated generator example. Thanks,

# John J Barton (14 years ago)

On Mon, Oct 10, 2011 at 3:09 PM, Brendan Eich <brendan at mozilla.com> wrote:

On Oct 10, 2011, at 1:41 PM, Bob Nystrom wrote:

On Mon, Oct 10, 2011 at 1:33 PM, Dean Landolt <dean at deanlandolt.com>wrote:

Here's an example:

let tree = [['a', 'b', 'c'], [['d', 'e'], 'f'], ['g']];

let inOrder = walk(tree); for (node of walk(tree)) alert(node); // a, b, c, d, ...

walk(tree) { if (typeof tree == 'string') { yield tree; // leaf } else { yield* walk(tree); // branch } }

What would the above look like without generators?

Woah there -- where does this syntax come from? Was walk(tree) {...} supposed to be function* walk(tree) {...} instead? Or is this intended to represent some sort of method generator? If the latter, doesn't this need some mechanism to distinguish it from a non-generator method?

Whoops, my mistake. Too much time working on the class proposal where "function" isn't needed for methods.

I spy a Dart ;-).

Yes, that should be function*.

Still a great delegated generator example. Thanks,

Bob sent me a more complete and much more convincing example off line. It was more convincing because he had three different algorithms use the same iterator. Did not convert me but I am at least moved out of the "no way" column.

jjb

# Rick Waldron (14 years ago)

Is it possible to share the example code?

# Bob Nystrom (14 years ago)

This fell off the list. Re-adding it as requested. :)

  • bob

---------- Forwarded message ---------- From: Bob Nystrom <rnystrom at google.com>

Date: Wed, Oct 5, 2011 at 1:39 PM Subject: Re: On "I got 99 problems and JavaScript syntax ain't one" To: John J Barton <johnjbarton at johnjbarton.com>

On Wed, Oct 5, 2011 at 11:06 AM, John J Barton <johnjbarton at johnjbarton.com>wrote:

I think I was the one that was not clear. Recursion on a data structure is a bit tricky but at least the call stack gives you a cursor into a data structure as a guide to the state of the processing. I've had good experience with it. My brief investigation of generators confused me because I couldn't find the state of the iterator in the debugger.

Yeah, that's a bit annoying. The callframe for the generator has been reified and moved aside. If you put a breakpoint in the generator function, you can get to it in your debugger the next time the iterator is iterated.

Sorry, I just can't imagine that generators will ever be used any significant fraction of the current use of closures in JS.

The new built-in methods for iterating over objects (keys(), values() and items()) are defined using them. They won't be used everywhere, but they will be used. They're like a cheese grater: not something you use for every meal, but unbelievably convenient for the meals that require them.

var tree = [['a', 'b', 'c'], [['d', 'e'], 'f'], ['g']];

function walkLeaf(leaf) { console.log(leaf); }

function walkTree(tree) { tree.forEach(function(treeOrLeaf) { if (typeof treeOrLeaf == 'string') { walkLeaf(treeOrLeaf); } else { walkTree(treeOrLeaf); } }); }

Your walkTree() isn't a generic function for traversing a tree like walk(), it's a specific function for logging a tree. You could change it to take a callback, of course, but then the callers lose the ability to do flow control while iterating. How would you handle this?

function findLeaf(tree, leaf) { for (node of walk(tree)) { if (node == leaf) return node; } }

Or:

function partition(tree, cut) { let nodes = walk(tree); let before = []; for (node of nodes) { if (node == cut) break; before.push(node); }

let after = []; for (node of nodes) after.push(node); return [before, after]; }

# Mark S. Miller (14 years ago)

On Wed, Aug 31, 2011 at 10:52 AM, Lasse Reichstein < reichsteinatwork at gmail.com> wrote:

On Tue, Aug 30, 2011 at 11:46 PM, David Bruant <david.bruant at labri.fr> wrote:

Le 30/08/2011 21:59, Lasse Reichstein a écrit :

A reliable .call could probably also achieve the same.

A reliable .call could be achieved by composing a reliable .bind and the function call syntax.

True. The Bind operation is the currying of the Call operation.

Ah, that got me thinking. I can do var CallFunction = Function.prototype.call.bind(Function.prototype.call); since bind does give a different way to set the this-object for a call. This can be done once, before anybody gets to mangle the builtins, and can be stored for afterwards. Excellent!

On Wed, Oct 5, 2011 at 10:17 AM, Lasse Reichstein < reichsteinatwork at gmail.com> wrote:

(On the other hand, it's actually a fun experience to write Javascript code that can't be affected by a modified environment - the same way three-legged races are fun :)

On Wed, Oct 5, 2011 at 12:23 PM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote:

dunno how we ended up here but I would rather use this approach in a private scope:

var // used to trap function calls via bind invoke = Function.call, // normal use cases bind = invoke.bind(invoke.bind), apply = bind(invoke, invoke.apply), call = bind(invoke, invoke) ;

var hasOwnProperty = bind(invoke, {}.hasOwnProperty);

hasOwnProperty({key:1}, "key"); // true call([].slice, [1,2,3], 1); // 2,3 apply([].slice, [1,2,3], [1]); // 2,3

, Andrea Giammarchi

Since some implementations of Function.prototype.bind are still a bit rusty, I thought about how to do this using just call and apply. Here's what I came up with:

var builtInApplyFn = Function.prototype.apply; var builtInCallFn = Function.prototype.call; var builtInSliceFn = Array.prototype.slice;

builtInApplyFn.reallyCall = builtInCallFn; Function.prototype.apply = function(thisArg, argArray) { return builtInApplyFn.reallyCall(this, thisArg, argArray); };

function apply(func, thisArg, argArray) { return builtInApplyFn.reallyCall(func, thisArg, argArray); } function call(func, thisArg, var_args) { var args = builtInApplyFn.reallyCall(builtInSliceFn, arguments, [2]); return builtInApplyFn.reallyCall(func, thisArg, args); } function method2Function(meth) { return function(self, var_args) { var args = builtInApplyFn.reallyCall(builtInSliceFn, arguments, [1]); return builtInApplyFn.reallyCall(meth, self, args); }; }

var hop = method2Function(Object.prototype.hasOwnProperty); var slice = method2Function(builtInSliceFn); var concat = method2Function(Array.prototype.concat);

The name "method2Function" is just awful but I haven't thought of a better one. It's a hard thing to name. Suggestions appreciated.

# Brendan Eich (14 years ago)

On Oct 7, 2011, at 6:51 AM, Mikeal Rogers wrote:

On Thu, Oct 6, 2011 at 5:08 AM, Brendan Eich <brendan at mozilla.com> wrote: On Oct 4, 2011, at 10:52 AM, Mikeal Rogers wrote:

But, some of them simply double the semantics and syntax in the language without a path to deprecate previous syntax. I'm a big fan of let, but if you don't deprecate var we're going to have to contend with new programmers keeping two sets of scoping rules in their head.

You mean by deprecate what, exactly?

Web JS is full of var. Making any attempt to migrate a big hunk of it to ES6 require replacing all 'var' with 'let' is a huge tax, since scoping works differently.

Ok, how about saying if you use 'let' in a function or at top level, you can no longer use 'var'? That's less of a tax on average, but for a long program or single function, it's as bad.

This is exactly what I was getting at.

Andreas Rossberg brought it up. We can put it on the agenda for the November meeting, but it could be better to discuss here first, if people have specific migration stories involving let and var (say, from Firefox add-on or browser JS).

My main point was that syntax is hard. But syntax is UI and JS's UI has real usability bugs. I'm glad you find it easy to teach. That's not the only consideration though, because after people learn a language, as they keep using it they do progress to become fluent, even expert, at it, and its usability problems come to the fore.

Semantics for experts is fine so long as the syntax doesn't confuse beginning to intermediate programmers. Like I said, I think the destructuring proposal is a great example of syntax that makes the semantics behind it obvious especially when compared to what it takes to accomplish the same task now.

I would contrast that with generators. With ES5's forEach, map and filter, which are quite simple and obvious,

The meanings of the optional parameters are not super-obvious, but ok.

I wonder why the semantics of generators can't be achieved in a way that is clearer to less than expert programmers.

What's the problem? You didn't say.

The semantics of generators must be such that the compiler can tell when a function is a generator. So something is going to signify "this function is a generator".

(We already went around the block with using "generator" as a keyword -- that's not a reserved future word so it would need to be reserved as a breaking change, or possibly only if it comes after a line terminator, but then anonymous generators are still incompatible. I.e., you could have JS today of this form:

x = generator (a, b) { }

which if generator names a callable object and a and b are bound, is perfectly legal.)

I also haven't touched classes yet. Just saying the word makes me cringe a little, but once i get over my initial emotional reaction I think about how difficult it is currently to juggle code that is using traditional prototypical inheritance and code that is using an entirely different pattern people use to hack class inheritance in today.

What other pattern? The closure pattern is not really "incompatible", just different. You can even mix the two.

Having just a syntax, even without any more semantics than people already add today, could reduce that confusion.

That was the hope. Seems like too many requirements, including ones we can't agree to meet now and yet also can't future-proof against, got piled on top.

I'm still on the fence about it because I'm so initially reactionary about the word itself... "class".....

Yes, I cringe a bit too. Would "factory" be better? It has the same problem as "generator", though -- it is not a future reserved word.

# John J Barton (14 years ago)

On Wed, Oct 12, 2011 at 2:08 PM, Brendan Eich <brendan at mozilla.com> wrote:

On Oct 7, 2011, at 6:51 AM, Mikeal Rogers wrote:

On Thu, Oct 6, 2011 at 5:08 AM, Brendan Eich <brendan at mozilla.com> wrote:

On Oct 4, 2011, at 10:52 AM, Mikeal Rogers wrote:

But, some of them simply double the semantics and syntax in the language without a path to deprecate previous syntax. I'm a big fan of let, but if you don't deprecate var we're going to have to contend with new programmers keeping two sets of scoping rules in their head.

You mean by deprecate what, exactly?

Web JS is full of var. Making any attempt to migrate a big hunk of it to ES6 require replacing all 'var' with 'let' is a huge tax, since scoping works differently.

Ok, how about saying if you use 'let' in a function or at top level, you can no longer use 'var'? That's less of a tax on average, but for a long program or single function, it's as bad.

This is exactly what I was getting at.

Andreas Rossberg brought it up. We can put it on the agenda for the November meeting, but it could be better to discuss here first, if people have specific migration stories involving let and var (say, from Firefox add-on or browser JS).

I tried |let| briefly in Firebug, then backed it out. I don't recall exactly why, but I do recall thinking I had been mislead. Maybe there are some styles of JS where var vs let is a big deal, but not for me. (I am a fan of varsWithLongNames). I don't think var caused me a problem more than a couple of times. Thus to me it seems like a big deal about nothing.

Rather than a funky rule ("at top level..."), "using stricter" makes more sense. That way pressure to change comes from other devs telling you best practice rather than compiler error messages you can't figure out.

jjb

# Dean Landolt (14 years ago)

On Wed, Oct 12, 2011 at 5:08 PM, Brendan Eich <brendan at mozilla.com> wrote:

On Oct 7, 2011, at 6:51 AM, Mikeal Rogers wrote:

On Thu, Oct 6, 2011 at 5:08 AM, Brendan Eich <brendan at mozilla.com> wrote:

On Oct 4, 2011, at 10:52 AM, Mikeal Rogers wrote:

But, some of them simply double the semantics and syntax in the language without a path to deprecate previous syntax. I'm a big fan of let, but if you don't deprecate var we're going to have to contend with new programmers keeping two sets of scoping rules in their head.

You mean by deprecate what, exactly?

Web JS is full of var. Making any attempt to migrate a big hunk of it to ES6 require replacing all 'var' with 'let' is a huge tax, since scoping works differently.

Ok, how about saying if you use 'let' in a function or at top level, you can no longer use 'var'? That's less of a tax on average, but for a long program or single function, it's as bad.

This is exactly what I was getting at.

Andreas Rossberg brought it up. We can put it on the agenda for the November meeting, but it could be better to discuss here first, if people have specific migration stories involving let and var (say, from Firefox add-on or browser JS).

My main point was that syntax is hard. But syntax is UI and JS's UI has

real usability bugs. I'm glad you find it easy to teach. That's not the only consideration though, because after people learn a language, as they keep using it they do progress to become fluent, even expert, at it, and its usability problems come to the fore.

Semantics for experts is fine so long as the syntax doesn't confuse beginning to intermediate programmers. Like I said, I think the destructuring proposal is a great example of syntax that makes the semantics behind it obvious especially when compared to what it takes to accomplish the same task now.

I would contrast that with generators. With ES5's forEach, map and filter, which are quite simple and obvious,

The meanings of the optional parameters are not super-obvious, but ok.

I wonder why the semantics of generators can't be achieved in a way that is clearer to less than expert programmers.

What's the problem? You didn't say.

The semantics of generators must be such that the compiler can tell when a function is a generator. So something is going to signify "this function is a generator".

(We already went around the block with using "generator" as a keyword -- that's not a reserved future word so it would need to be reserved as a breaking change, or possibly only if it comes after a line terminator, but then anonymous generators are still incompatible. I.e., you could have JS today of this form:

x = generator (a, b) { }

which if generator names a callable object and a and b are bound, is perfectly legal.)

You have to admit, this is highly unlikely. I know there are uses for yield-less generators (at least, so I've been told -- can you remind me of the specific cases?), but if code has to be contorted into the shape of the above example for it to be ambiguous I'm not inclined to be terribly sympathetic to the rare sucker that falls into this trap during conversion.

I could also see this as causing problems for someone authoring in harmony code and using generator as the name for a method shorthand. But meh, if they know method shorthand they should know that generator's newly reserved.

But this reminds me -- has anyone proposed a method shorthand for generators? Is it worth it? If so, it occurs to me that moving the * to after the head for both function and method generators could be one way to unify the two:

function()* { yield ... } var x = { foo()* { yield ... } }

ISTR a comment Brendan made about the current function* syntax keeping the grammar simple -- I'm not sure how that would apply to the above suggestion.

[snipped the rest]

# Mikeal Rogers (14 years ago)

On Oct 12, 2011, at October 12, 201110:08 PM, Brendan Eich wrote:

This is exactly what I was getting at.

Andreas Rossberg brought it up. We can put it on the agenda for the November meeting, but it could be better to discuss here first, if people have specific migration stories involving let and var (say, from Firefox add-on or browser JS).

I don't know what official capacity it was brought up in but i know Alex once mentioned to me the idea of using modules to deprecate var. Basically, within a module var is no longer allowed. That's another idea.

Either way, I think it should be a priority to have a deprecation strategy in place for var in ES6, I don't have a strong opinion about what it should be.

I wonder why the semantics of generators can't be achieved in a way that is clearer to less than expert programmers.

What's the problem? You didn't say.

The semantics of generators must be such that the compiler can tell when a function is a generator. So something is going to signify "this function is a generator".

(We already went around the block with using "generator" as a keyword -- that's not a reserved future word so it would need to be reserved as a breaking change, or possibly only if it comes after a line terminator, but then anonymous generators are still incompatible. I.e., you could have JS today of this form:

x = generator (a, b) { }

which if generator names a callable object and a and b are bound, is perfectly legal.)

A generator keyword is much clearer and avoids confusion but as you say, it's not a reserved word and has practical issues.

The issues you bring up are serious, all I'm saying is that by attaching additional semantics to function we continue to perpetuate confusion about what functions are in javascript and reducing confusion, for me, is more important. Others may not agree.

I also haven't touched classes yet. Just saying the word makes me cringe a little, but once i get over my initial emotional reaction I think about how difficult it is currently to juggle code that is using traditional prototypical inheritance and code that is using an entirely different pattern people use to hack class inheritance in today.

What other pattern? The closure pattern is not really "incompatible", just different. You can even mix the two.

What I meant was, object A uses class style inheritance and class B uses vanilla prototype inheritance and there isn't an obvious signal that they are different or which style I should use if I'm going to extend them if I'm a less than expert programmer.

This is something we might solve with classes in ES6.

Having just a syntax, even without any more semantics than people already add today, could reduce that confusion.

That was the hope. Seems like too many requirements, including ones we can't agree to meet now and yet also can't future-proof against, got piled on top.

IMO, ditch all the additional semantics. Make it pure cane sugar. It adds clarity to the language around a pattern that is already popular. If people are clamoring for all these extra semantics then it'll be obvious what should go in by ES7.

I'm still on the fence about it because I'm so initially reactionary about the word itself... "class".....

Yes, I cringe a bit too. Would "factory" be better? It has the same problem as "generator", though -- it is not a future reserved word.

I don't think my, or your, apprehension to the word itself is representative of most new users. We'll get over it, we have to, it's not like we're going to start programming Dart :P

# Brendan Eich (14 years ago)

On Oct 12, 2011, at 5:28 PM, Dean Landolt wrote:

On Wed, Oct 12, 2011 at 5:08 PM, Brendan Eich <brendan at mozilla.com> wrote: On Oct 7, 2011, at 6:51 AM, Mikeal Rogers wrote:

I wonder why the semantics of generators can't be achieved in a way that is clearer to less than expert programmers.

What's the problem? You didn't say.

The semantics of generators must be such that the compiler can tell when a function is a generator. So something is going to signify "this function is a generator".

(We already went around the block with using "generator" as a keyword -- that's not a reserved future word so it would need to be reserved as a breaking change, or possibly only if it comes after a line terminator, but then anonymous generators are still incompatible. I.e., you could have JS today of this form:

x = generator (a, b) { }

which if generator names a callable object and a and b are bound, is perfectly legal.)

You have to admit, this is highly unlikely.

It's not a matter or likelihood. We need a backward compatibility (apart from five fingers of fate, four of them giving early errors on incompatible code migration). We need an unambiguous grammar. And we need usable syntax. Adding a [no LineTerminator here] generator ... production fails two of those three.

But this reminds me -- has anyone proposed a method shorthand for generators?

Yes, it's easy:

var x = { *foo() { yield ... } }

The * goes after 'function' and before the optional name, in the current proposal. So for method shorthand, where there is no 'function' but there must be a name, the * goes before the generator method's name.

This is yet another problem (after [computedNameExpr]:...) for making commas optional, as discussed.

# Brendan Eich (14 years ago)

On Oct 12, 2011, at 7:40 PM, Mikeal Rogers wrote:

What I meant was, object A uses class style inheritance and class B uses vanilla prototype inheritance and there isn't an obvious signal that they are different or which style I should use if I'm going to extend them if I'm a less than expert programmer.

This is something we might solve with classes in ES6.

Yes, the goal of classes since the beginning of Harmony was "classes as sugar". No new semantics if we could help it. The original sketch by MarkM used the closure pattern, but we ended up favoring prototypes. So classes as proposed desugar to constructor functions. No interoperation barrier with old code that does it by hand.

Having just a syntax, even without any more semantics than people already add today, could reduce that confusion.

That was the hope. Seems like too many requirements, including ones we can't agree to meet now and yet also can't future-proof against, got piled on top.

IMO, ditch all the additional semantics. Make it pure cane sugar. It adds clarity to the language around a pattern that is already popular. If people are clamoring for all these extra semantics then it'll be obvious what should go in by ES7.

We factored out private already, so the only additional semantics have to do with instance variable initialization. Some want at least future-proofing for a way to make a constant instance variable where reading it before it has been initialized is an error. Leaving that out is of course a good idea, but at least Waldemar still objects that we may be future-hostile by doing even minimal classes.

At this point, I'm not sure how to get unstuck.

# Allen Wirfs-Brock (14 years ago)

On Oct 13, 2011, at 8:36 AM, Brendan Eich wrote:

On Oct 12, 2011, at 5:28 PM, Dean Landolt wrote:

But this reminds me -- has anyone proposed a method shorthand for generators?

Yes, it's easy:

var x = { *foo() { yield ... } }

The * goes after 'function' and before the optional name, in the current proposal. So for method shorthand, where there is no 'function' but there must be a name, the * goes before the generator method's name.

This is something that I'm been meaning to bring up:

var x = { #*foo() {yield } };

Not necessarily a parsing problem but there has been push back against sequences of property prefixes.

This is yet another problem (after [computedNameExpr]:...) for making commas optional, as discussed.

I'm not sure that either is really a serious usability issue, but I agree that it's on my plate to demonstrate otherwise.

# Brendan Eich (14 years ago)

On Oct 13, 2011, at 3:00 PM, Allen Wirfs-Brock wrote:

On Oct 13, 2011, at 8:36 AM, Brendan Eich wrote:

On Oct 12, 2011, at 5:28 PM, Dean Landolt wrote:

But this reminds me -- has anyone proposed a method shorthand for generators?

Yes, it's easy:

var x = { *foo() { yield ... } }

The * goes after 'function' and before the optional name, in the current proposal. So for method shorthand, where there is no 'function' but there must be a name, the * goes before the generator method's name.

This is something that I'm been meaning to bring up:

var x = { #*foo() {yield }

It seems to me the order should be *# since with generator functions, the * goes after the function keyword, with best style favoring no space to left of *, one space to right.

Also, in HoMD, I made # an identifier prefix.

};

Not necessarily a parsing problem but there has been push back against sequences of property prefixes.

That may be an edge case we can live with. That it could be done doesn't mean it will be done often enough to make for Beetle Bailey appearances.

This is yet another problem (after [computedNameExpr]:...) for making commas optional, as discussed.

I'm not sure that either is really a serious usability issue, but I agree that it's on my plate to demonstrate otherwise.

Thanks,

# Allen Wirfs-Brock (14 years ago)

On Oct 13, 2011, at 12:07 PM, Brendan Eich wrote:

On Oct 13, 2011, at 3:00 PM, Allen Wirfs-Brock wrote:

On Oct 13, 2011, at 8:36 AM, Brendan Eich wrote:

This is something that I'm been meaning to bring up:

var x = { #*foo() {yield }

It seems to me the order should be *# since with generator functions, the * goes after the function keyword, with best style favoring no space to left of *, one space to right.

Also, in HoMD, I made # an identifier prefix.

And also: var y = { get #bar() {}, set #[3+4] (v) {} };

It seems to me that by placing the # always next to the name is associating it with the wrong thing. It isn't property name that is being frozen, it is the property definition. I would expect instead to see:

var y = { #get bar() {}, #set [3+4] (v) {} };

# Brendan Eich (14 years ago)

On Oct 13, 2011, at 3:25 PM, Allen Wirfs-Brock wrote:

I would expect instead to see:

var y = { #get bar() {}, #set [3+4] (v) {} };

I see your point. Still don't like it, though -- the C pre-processor (dmr RIP) is making me flinch.