Re: First crack at a Streams proposal
> That request is nearly always followed with an (explicit or implied) > "And if it can be, why should we do it? Leave it to libraries!" > statement. If you did not intend this, then I apologize. Well, actually, I think that we *should* do it with libraries for a bit, because I have come to believe from repeated experience that this is the only reliable way to evaluate patterns, and that forcing acceptance of a specification in advance of trials leads to a lot of error. Again, qv promises, map/set, etc. That's how it's done because it works. > You need Object.observe to do reactive values as an event stream. You > can do event streams (turning DOM Events into a stream) with today's > JS. Are you proposing reactive values as an event stream? It seemed like your proposal was mostly pretty simple interfaces. > Apologies for the mismatch in expectations. I recognize that > reference implementations are more *customary* when proposing things > in JS that don't depend on new primitives. Instead, I provided a spec > that sketched out appropriate details (and can be filled in further as > necessary). For the purpose of discussion of the idea, the two should > be roughly equivalent. I disagree. They're not equivalent at all. Not even roughly, not even close. One can be tested, reviewed, and subjected to experiments in the real world. The other is imaginary. > Again, I'm aware that JS proposals often come with a reference > implementation, or at least a sketch of one. That's not strictly > necessary to review and talk about a proposal, however. To do so responsibly, I believe that it is. > If you think > that you are unable to even discuss the proposal without such a > reference implementation, then I'm sorry that we will have to lose > your voice until I have the time and engery to provide such. Actually, I strongly doubt *anyone* is able to adequately discuss the pros and cons of a proposal like this without an implementation. I don't have anything else to contribute until there is a reference implementation. I'm not super motivated to write it myself, but I'd be happy to test it out, or consult about any sticky issues you run into, etc. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: First crack at a Streams proposal
On Sat, Apr 20, 2013 at 12:47 PM, Tab Atkins Jr. wrote: > On Sat, Apr 20, 2013 at 9:19 AM, Isaac Schlueter wrote: >> I'm not seeing what in this proposal can't be implemented in >> JavaScript as it is today. Is there an implementation of this >> somewhere? Are there any programs that use these streams? > > This is a fully-general counter-argument against literally everything > that doesn't require new primitives, and so is useless as an actual > argument. It's not fully-general counter-argument, because it's not an argument. It's a request for more information. Until I have that information, I don't have enough information to form a reasonable opinion. I read your proposal. It appears to be something that is implementable with today's current JavaScript. Am I mistaken? If so, how so? (Ie, what new language semantics or primitives are required?) If I'm not mistaken, then where's the reference implementation? I don't even see example code. I figured that I must be missing something. You're wrong about what it would damn, in every case. > It would damn Promises/Futures Promises had many, many iterations in working code long before a specification was ever proposed. > Sets, Maps Both required new language semantics. But there WERE reference implementations of both, long before either of those reached a spec. > and a number of other new things. Please be more specific. There are many numbers. Don't allude to the vastness of your point, just make it, or don't. Search npm and github before making claims about what things would be damned by the request for a reference implementation in advance of a specification. > Please note that the proposal topping this thread is already > long-obsolete. Then please update the thread with the updated proposal, and preferably a link to the github account with the reference implementation, if such a thing exists. If such a thing does not exist, please explain why it is not feasible to write an implementation of this with today's language semantics. If I seem a bit impatient, it is because I am eager to have an opinion about this idea of yours, but I find myself incapable of responsibly having an opinion without seeing it in action. As you say, the concept of event streams appears in many libraries. I work daily with Node.js, which is full of event emitters and binary data streams. You mentioned that it would be easy to implement binary streams on top of your streams idea. I'd like to see that. I know from firsthand experience that streams can be surprisingly hard to get right. In my opinion, if you can't easily implement TCP, TLS, and Zlib on a stream implementation, then you haven't gotten it right. So, the fact that an implementation has not yet been shown seems quite strange to me, because that would be the *first* thing that I'd expect anyone would want to see, and it seems like it'd only take a few hundred lines of code to do. I say that because other "streaming" FRP pattern libraries have been implemented in just a few hundred lines. Look at the work of Dominic Tarr (dominictarr) or Irakli Gozalishvili (gozala) on npm and github. Until there is an implementation, I don't really see what there is to talk about. As I said, this is not a counter-argument, because as far as I'm concerned, there's nothing to even argue about! ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: First crack at a Streams proposal
I'm not seeing what in this proposal can't be implemented in JavaScript as it is today. Is there an implementation of this somewhere? Are there any programs that use these streams? On Mon, Apr 15, 2013 at 9:19 PM, Tab Atkins Jr. wrote: > On Mon, Apr 15, 2013 at 5:26 PM, Kevin Gadd wrote: >> OK, it sounds like this is sort of a 'lossy' stream concept, then, in that >> if you fail to call next() early enough, you can miss data from the stream? >> I can see how that would be acceptable for certain use cases. To me though, >> this limits use of the primitive. >> >> Here's a hypothetical. I'm building an instant messaging webapp - think >> google talk - and I want a 'stream' that represents the status of my online >> buddies. So each time someone goes online/offline, that would come through >> the stream. >> >> It sounds like with this design, were I to use next() to pull data out of >> the stream, any online status changes that have occurred before I called >> next() are lost forever, because at any given time all calls to next() >> return a future for the 'next update'. This means that if the portion of my >> service responsible from the contact list starts later than the actual >> network backend, it can miss status changes and end up with a partial >> picture of the state. Maybe that's ok. > > Yes, my current model doesn't buffer changes before the first > listener. This is the correct behavior for most DOM cases, but I see > how for a lot of other cases it's less good. By default, you might > want to have that buffer, so the first consumer gets to see all the > history, at least. (If you want multiple consumers to all get the > history, you should opt into that explicitly via some slightly less > convenient API, as it means infinite buffering.) > >> Similarly, it sounds like given this model if I have 3 consumers, and they >> all call next() once to get values, they have to be absolutely certain to >> call next() again *as soon as* the Future from the previous next() gets >> data. If they do the 'right thing' that you normally do in Future-oriented >> scheduling, where a future being activated results in a task being scheduled >> to do work, it's possible to miss data, given a flow like this: > > `next` is for when you just care about the very next time something > happens. If you care about all the events that come out, use `listen` > instead. > > It looks like many existing APIs use `next` for more pull-based > purposes, where the stream will buffer data until someone pulls it out > with `next`. My current API is explicitly *not* pull-based, but it's > easy to imagine a subclass that is. > >> Another question: Given this sort of 'synchronized' update model, what >> happens if two consumers both cause data to be pushed into the stream? There >> are two values to send out, but next() only has room for one value. Does the >> second value get thrown away? Does an exception get raised by the second >> push? I don't know how you can ensure that all the consumers will see the >> second value. > > Same thing - consumers should be using `listen` if they want all the > data. That's the "default" way to interact with a stream in my > proposal. > >> I think I will have to echo others' thoughts here that this really doesn't >> seem like a 'Stream' API. It does not match the semantics of any Stream >> primitive/concept I have ever encountered in an API. > > Yes, the name seems to be confusing people. On the other hand, I find > a lot of the other existing names hopelessly opaque or awkward - > Signal doesn't mean much to me, and Observable is too abstract. > Stream is just the right kind of name to convey "a stream of updates", > but unfortunately the name is co-opted by binary IO streams. :/ > > ~TJ > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: `free` operator
So, yes, you can certainly use debugging tools to find which objects are leaking. But, there are times when you have a program where something is leaking, and you read through the code, and see that there is no possible way that it could be leaking (but it is, as reality sometimes stubbornly refuses to be told what to do.) Use-after-free bugs are not great, but they are relatively easy to track down. And, in general, a program that crashes when it does something wrong, is handling it exactly right. Slowly leaking memory is much harder to diagnose, and usually much harder to correct. We've got some band-aids in place in the node http.js file to prevent parser leaks. A more forcible free() method would have made it much easier. The long-term solution is to rewrite the program so that it's not so badly architected, but as is so often the case, we didn't realize the architectural mistakes until we had made them, and fixing them is quite costly. (Node's http implementation will get a massive refactor in 0.12.) Yehuda's "action at a distance" complaint is definitely a valid concern. However, note that an object can't be freed unless you have a reference to the object. Thus, any code that would set my reference to undefined could only do so if it was also capable of mutating the object in any other way (adding/removing properties, etc.) So, we already have this: function () { // acquire a ref from some external code // no way of knowing what else is sharing this object var x = func() x.foo = 'bar' // other code... doAnotherThing() // not guaranteed! assert(x.foo === 'bar') } Whenever you have a reference to an object that is shared with some other code, there's the potential for action at a distance. The proposal here is to make that action a bit more powerful. I don't agree that it's necessarily a problem in production. We free objects in other languages all the time. On Fri, Oct 26, 2012 at 5:11 PM, Patrick Mueller wrote: > On Fri, Oct 26, 2012 at 11:51 AM, John J Barton > wrote: >> >> Debugging tools lag other tools in part because test-cases or >> use-models are hard not readily available. > > > But the only debugging tools we really have are proprietary low-level APIs > (eg, V8 debug stuff), and some existing debug ui frameworks (eg, Web > Inspector). The barrier is so, so high for this stuff. Compared to a > number of other environments where the barrier is not so high. Eg, in C, if > you're debugging memory issues, switching to using a debug malloc library > isn't a huge barrier. > > It would be nice to lower the barrier, expose some "debug" stuff in JS. > Implying that I want "debug APIs" available in JS, and I want to write my > debug helpers in JS. > > V8's --expose-debug-as (or whatever) trick is a step in the right direction. > It would be nice to have some commonality here, so I don't have to write one > set of debug helpers for V8, another for JSC, another for *Monkey, etc. > >> >> The js-tools group would be ideal for more discussions of these >> issues: https://groups.google.com/forum/?fromgroups=#!forum/js-tools > > > Ah, nice. I'll stop pestering here, and start pestering there. :-) > > -- > Patrick Mueller > http://muellerware.org > > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: `free` operator
On Fri, Oct 26, 2012 at 1:35 AM, Shawn Steele wrote: > I sort of have a fundamental problem with the solution. Eg: If it were > actually unused, it'd be GC'd. Since it isn't GC'd, something must be > holding a reference to it. So if you force it to be gone, or clear all the > properties, or whatever, seems to me that then you'd just start throwing > random errors in the code that tried to use the "freed" object? That might > be even harder to track down. On the contrary, "TypeError: Cannot read property 'prop' of undefined", with a stack trace, is WAY easier to track down than "The RSS on my server gradually rises, until the operating system kills it, which happens about every 4 hours." Fast failure is not as good as success, but it's better than anything else. > On Thu, Oct 25, 2012 at 4:16 PM, Isaac Schlueter wrote: >> It'd be really nice if JS had a way to explicitly delete an object. > > I guess you mean ... a way to set all the refs to a object to undefined. Yes, exactly. On Fri, Oct 26, 2012 at 1:20 AM, John J Barton wrote: >> var obj = {} >> var foo = { ref: obj } > > I assume that in your real life, you don't know 'foo' but somehow you > know that foo.ref is never used? Well, you know that IF foo.ref is used, it's an error, and ought to throw. Also, it's quite easy to check if the property exists, and set it to a new object if so. It's common to have things like: if (!this._parser) { this._parser = new ParserThingie(); } In this example, imagine that parsers are expensive to create. So, we try to reuse them (danger!), and over time, our program grows until we have some code paths where the parsers are not getting all of their data removed properly. If the parser has a ref to an object that has a reference to some other thing, etc., then you've got a memory leak. This exact situation happened in Node's HTTP library a few months ago, and was very tedious to fix. We quite easily identified one of the things in the chain, and that it must have been linked in some way to an HTTP parser (or else it would have been GC'ed). It would have been much easier to just find the point where we know that the HTTP response object should be "finished", and forcibly remove any references to it. > Since you know "obj" can you set it to be a getter that returns undefined? Yeah, but the purpose of this is to take *away* the ref that you already *have*. What good is a getter that returns undefined, once you've already gotten it? Closing the barn door after the horse has left. > Deleting all of the properties of obj would solve the problem as well I > assume. But that is a bit more whack-a-mole, and expensive. Ultimately, what we did was move all of the addon properties on parsers to a single object, and delete that object when we re-use the http parser. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
`free` operator
It'd be really nice if JS had a way to explicitly delete an object. Occasionally, in complex programs, you can find yourself with a situation where a certain type of object is leaking. However, even if you track down what the object is, and find the exact point in your program where you ought to have no references to it, it's not always obvious to know what might be holding a reference still. It's tempting to do this, and newcomers often think that this helps, but of course, it does nothing: function doStuff() { // some object that we're doing stuff with... someObject.someMethod() // now we know we're done, and there should be no refs. // but, there are, and they're leaking. // I know! I'll do this: delete someObject // surprise! that does nothing. } What do you folks think about a "free" operator (or something like it) that would actually do what `delete` looks like it does? var obj = {} var foo = { ref: obj } var obj2 = obj free obj // obviously this syntax probably won't work, since 'free' is not a reserved word already assert(obj === undefined) assert(foo.ref === undefined) assert(obj2 === undefined) So, any references to the freed object would be set to undefined, and presumably at some point, the GC will harvest it. Yes, yes, I know, the proper way to fix a memory leak in JS is to properly manage references, but sometimes that means rewriting this complicated app, and it's leaking memory now, in production. Has this been discussed before? ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ES Modules: suggestions for improvement
Sorry for my long delay in responding. On Fri, Jun 29, 2012 at 4:33 PM, David Herman wrote: >> var fs = require('fs') >> // no path here... >> function notCoveredByTests () { >> fs.open(path.resolve("yabbadabba"), ...) >> } > > Right. > >> How would any of this solve that? > > Because `path` is unbound, and static variable checking reports that as an > error. And this works because modules don't share global namespace with one another? (If they do share global space, then how would the static checker know that it won't be assigned to a global 'path' by that time?) > I'm going to mull this more. I agree it's a worthwhile goal. But I'd like to > find a way to keep the syntax as lightweight as possible and yet not > interfere with static resolution. Sounds good. I'm interested in what you come up with. > But we should not force this style on programmers. It's not forcing anything on programmers. If you want to export a bag of functions, then put the functions on an object, and export the object. It *is* making it trickier to figure out how to add types and macros, but I'm less excited about those features than I am about making our existing problems easier to solve. > Even Node itself does not adhere strictly to that style -- look at the 'path' > or 'fs' libraries, for example. I consider that a mistake. And even there, there's a single "exports" object that methods are assigned to. > Same with the ES standard library: Math and JSON are both multi-export > (pseudo-)modules that just export functions. They export a single object that has functions attached to it. Math.pow(), JSON.parse, etc. export { parse: parse, stringify:stringify } > In these cases, there's no natural data abstraction needed, no class or > object with methods, just functions. To quote John Carmack, "Sometimes the > elegant implementation is just a function. Not a method. Not a class. Not a > framework. Just a function." The Carmack quote is exactly why "export one thing" is so important. Most modules should be a single function; not several things, not a collection of utility methods. >>> Moreover, it would be hostile to adding static constructs in the future, >>> such as macros, that can be exported from a module. >> Can you elaborate on that? > It took me a few days, but I wrote up some rationale for static module > resolution on my blog: > > http://calculist.org/blog/2012/06/29/static-module-resolution/ At the risk of seeming like a little bit of a luddite, it seems weird to me to make the "modules that export stuff" use case (which we have now) less awesome, in favor of the "modules that exports macros and types" use case (which is not a compelling problem right now). Granted, we don't have that use case because it doesn't exist. But maybe it could be done in a different way that doesn't necessitate multiple exports. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ES Modules: suggestions for improvement
On Wed, Jun 27, 2012 at 11:51 AM, David Herman wrote: > On Jun 27, 2012, at 11:15 AM, Isaac Schlueter wrote: > >> That was a bug caused by a lack of global isolation, which current >> module systems cannot fix. > > It was caused by accidentally creating a global variable instead of a local > variable. Not totally sure what you mean by global isolation? If you mean > giving separate modules separate global objects, I don't agree that that > would solve this kind of bug. He doesn't show us the whole code, but it looks > like it was local code that was accessing the (accidentally) global variable, > but probably different event handlers were interleaving and causing data > races. So, I've encountered two flavors of this in production, in my own programs: (The first in npm, the second in the no.de portal) 1. leaked global app.route("/my/login", function (req, res) { x = res.query.x || 100 if (x < 100) blerg() }) In testing, you don't spot the leaked global, and things work, because there's only one request at a time. Linters all catch this, and tests can check for leaked globals. 2. Module-local var var x = someThing // ... many lines later .. app.route("/my/login", function (req, res) { x = res.query.x || 100 if (x < 100) blerg() }) A linter *won't* catch this, since it'll assume that you meant to do exactly what you did. Global isolation won't catch it either, and neither will Harmony Modules or any existing require() thing. (And in fact, often you DO mean to do what this does!) I think this is one of the cases where we just have to make programming easier, by making choices that encourage smaller, more discrete modules. > Partly agree? I believe that obviating the *need* for globals is the core > purpose of a module system. I don't believe that modules should necessarily > be strictly separated. Modules should be given clean local scopes so that > they don't overwrite each other, but that doesn't mean they shouldn't be able > to still communicate via the global object. Right, perhaps isolation is the wrong word. Missing a "var" keyword should not be so hazardous, that's what I'm saying. > That bug was particularly bad because it was *assigning* to an accidentally > global variable. But in my personal experience I certainly forget to import > common libraries like 'path' and 'fs' in Node all the time and end up with > unbound variable references. When this happens in a control flow that got > missed by tests, then it can end up in production. You mean something like this? var fs = require('fs') // no path here... function notCoveredByTests () { fs.open(path.resolve("yabbadabba"), ...) } How would any of this solve that? >> var Foo = require("foo") >> var f = new Foo() > > Just import it directly: > > import Foo from "foo"; > var f = new Foo(); But wait... those are two different things, aren't they? Isn't yours more akin to: `var Foo = require('foo").Foo`? > I just disagree. I think it's fine if you like that style [one module exports > one thing], and you can use it. But we shouldn't force it on users. I'm having trouble articulating why it is that module.exports=blah is better than exports.blah=blah. Surely, you can just choose to only put one thing on the exports object, right? It seems obviously better to allow the flexibility, and I was strongly in favor of this early in node's history. However, after using it a lot, I've found that `exports.foo = bar` often ends up being more painful than `module.exports = foo`, even with the transitive issues. I'm not sure why that is, and "Go write couple hundred KLoC of module JS and then you'll get it" is not an argument, I know. > Moreover, it would be hostile to adding static constructs in the future, such > as macros, that can be exported from a module. Can you elaborate on that? >> How does this proposal address transitive dependency cycles? > > Better than yours. ;-P > >> Unfinished export objects? > > The exports are all there from the beginning but uninitialized. That's sort of like unfinished objects, then, but with the keys all set to undefined. So, then `export x = 10` hoists the `export x` and leaves the `x = 10` where it is, var-like? Does a_c === c, or not? > Maybe! Happy to discuss. I don't believe there's that much boilerplate. In > fact, there's *less* boilerplate than either CommonJS or AMD, and compared to > your sketches on your post I suspect the differences in character count could > be counted on one hand. It's quite a lot of new syntax, including special syntax for thi
Re: ES Modules: suggestions for improvement
On Wed, Jun 27, 2012 at 11:15 AM, Isaac Schlueter wrote: > import {myX: x, myY: y, z} from "foo" > // comparable to: > let {myX: x, myY: y, z} = require("foo") > Um.. I got the destructuring backwards, didn't I? > Of course not. You can export a mutable object if you want to. You can export > whatever you want. I seem to have missed that you already answered my question about freezing. Consider it withdrawn. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ES Modules: suggestions for improvement
> Well, this was a relatively high-profile example: > > http://blog.safeshepherd.com/23/how-one-missing-var-ruined-our-launch/ That was a bug caused by a lack of global isolation, which current module systems cannot fix. (Well, node *can* fix it with separate contexts, but only by harshly penalizing performance and breaking typeof, which we're not willing to do.) I think we all agree that global isolation is the core purpose of a module system. (Is that incorrect?) The question was whether there are in-the-wild bugs caused by typo-ing export names in current module systems. > The client chose to use *. You don't have to use * if you don't want to. > It's a convenience. It's unnecessary, afaict, and causes demonstrable harm in languages that have it. If it's just a convenience, then it should be cut out. > Clients are disallowed from mutating another module's exports. (That's one > of the things we're able to accomplish by making modules declarative rather > than totally dynamic.) Mutating *at all*? Ie, they're frozen? If I export an object, you can't decorate it? (If so, what does that restriction buy us? It seems kind of harsh.) > Here I have no idea what you're talking about. Nothing about ES6 modules > prevents you from locally controlling names. Local control over scope has > always been one of the foremost principles of the entire design. It's not exactly clear to me how I'd import foo's "x" as something other than "x", from reading http://wiki.ecmascript.org/doku.php?id=harmony:modules (Admittedly, I'm a lot better at parsing JavaScript than parsing JavaScript parsing rules.) Something like this? import {myX: x, myY: y, z} from "foo" // comparable to: let {myX: x, myY: y, z} = require("foo") Does this allow any way for the "foo" module to export *just* a single thing, as the top level result? How would this be expressed? var Foo = require("foo") var f = new Foo() If the answer is "that's not supported", then I think that's a significant gap. It encourages a "one module = one thing" style and is very easy to reason about. It would be better to give up multi-exporting in favor of exporting one thing, only. If I could get away with making that change in Node, I would have by now. How does this proposal address transitive dependency cycles? Unfinished export objects? // a.js import b from "b" export a = b // b.js import c from "c" export b = c // c.js import a from "a" export c_a = a export c = 10 // does c_a === c? This was one area where I mentioned in my blog post that new syntax for exporting seems like it might be warranted. With require() systems today, c_a is undefined, because the "c" export wasn't set yet. It's of course much worse when these are functions that call one another. All of the problems that I'm bringing up, which you're saying are solved by the Harmony:Modules proposal, is it possible to solve them with less new syntax and boilerplate? ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ES Modules: suggestions for improvement
On Wed, Jun 27, 2012 at 9:39 AM, Brendan Eich wrote: > First, what we propose is not type-checking. Oh, ok. I misunderstood. Let's not say another word about type checking :) > var foo = 42; > ... foop ... > > throws at runtime in ES1-5 if evaluation reaches the foop use, and (if you > wrap a module around that hunk of code, and there's no global foop property) > at compile-time (EarlyError) in ES6. I don't think that's a real problem. Can you point to in-the-wild bugs caused by this? Maybe it's a failure of imagination on my part. The "cost" I was referring to was: 1. added syntax 2. less obvious-for-humans-to-read programs Consider: module "foo" { export let x = 100; export let y = { z: 'zed' } } // far far away in another file entirely... import * from "foo"; import * from "baz"; console.log(x) // what? where did THAT come from? x++; // do other importers of foo see x change? if so, spooky! if not, why not? is it foo's x or not? y.z = 'zoo' // surely that must be shared, right? The compiler knows about x, but I don't. This is probably my biggest complaint about using C and C++. Managing exported symbols is not hard to automate, but it is hard to not-automate, and that makes it more painful than just fixing the bugs. Compare with: var foo = import "foo"; console.log(foo.x) // maybe undefined, but so what? We deal with undefined properties of objects all the time, and it's not really such a big deal. Typos are not a problem worth giving up "export one thing" semantics for, and dealing with symbol conflicts is worse. Just let me call my vars whatever I want; when I ask for your thing, give me your thing. Dumping a bunch of symbols into my local scope is intrusive. > Second, you are "not at all convinced". Ok, that's either attitudinizing and > padding an already long reply, or a line in the sand that doesn't say how > you would be convinced, so unanswerable. Sorry, you're right, that was unclear. I would be convinced by examples showing bugs in modern programs that would have been prevented by the proposed static export syntax. Ie, bugs that current state of the art module systems do not or cannot address, and which are causing actual problems. > We will never agree on "what JS is all about". Well, apparently we do wrt static type checking, actually :) But you're right. I'll leave esthetics out of it. Let's focus on practicality. > You seem to say lack of typo checking is not a gap in the language. Is this > a fair statement? Yes that is a fair statement. I don't see how we can add typo checking without also adding "you get to tell me what to call my local vars". In every other place in the language, I get to decide what my vars are called, and typo-checking happens locally, not at a distance. That's not a gap, that's a feature. The main gap in the language that I'd like to see filled by a module/loader spec is global leakage. As I see it, the rest is simply "how do we do that, without also removing module communication". Removing global leakage removes global communication, so in module-mode, we need a way for modules to communicate to one another, and for the host system to know which programs to load. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ES Modules: suggestions for improvement
I think a stand-up fight about this sounds wonderful. I am not at all convinced that typo-checking is anywhere near worth the price tag, or is even a problem. Most of the alleged needs for type-checking are a bit dubious to me; that's not really what JS is all about. It would be great for one of the static-export proponents to catalog some current problems in the wild today that this would address, with code examples that use modern module systems. Re: Conditional Importing Only allowing `import` at the top level sounds like an ok idea, but I'm not so sure it's necessary. Consider the current require() style: if (some_rare_condition()) { foo = require('foo') } In requirejs and browserify the 'foo' module will be *defined*, but never loaded (ie, prefetched, evaluated for deps, bundled, etc). In Node, it won't be read from the disk or evaluated (but if it's not there ON the disk, you'll have problems eventually, which is conceptually equivalent to having already been fetched, but without the pre-run safety check.) if (some_rare_condition()) { foo = import 'foo' } could be treated similarly. There is an import statement, so resolve it and define it. However, it's never actually evaluated/run until the first time the condition is hit, so the program text will be parsed for `import`s, but never actually executed. I am not aware of this being a surprise to many people in the current systems. > It's true you can use today's JQuery as is, but why would you use a new > client API or syntax and require only new browsers or else trans-compilation? > What's the benefit? I'm confused. Isn't `module "jquery" { ... $teh.Codez() ... }` already going to require only new browsers, as well as code editing or trans-compilation? Why is that less onerous than a new API or html tag, especially when the tag can desugar to the API? But, that being said, as I mentioned in the cited blog post, auto-exporting the global is a bit weird, at least. Making changes to old libraries is costlier than we tend to think, but usually not prohibitively so (and when it is, we just write new libraries). I definitely agree that speculating about the future is hazardous, which is exactly why I think that the module specification (and all ES specs, actually) should focus on the problems we have today, and aim to deliver value to today's programs. We should look at current common problems, and ask, "What is the minimum change to the language's semantics and syntax that will make *this problem* go away, without causing new problems, or preventing other solutions?" ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ES Modules: suggestions for improvement
On Tue, Jun 26, 2012 at 4:48 PM, Wes Garland wrote: > On 26 June 2012 18:36, Aymeric Vitte wrote: >> >> Node.js's way is good, except the "transitive dependency issue" mentioned >> in your post which in some cases indeed can cause problems. > Does Node not handle transitive dependencies per CommonJS Modules/1.0? Yes, node handles transitive dependencies via unfinished objects, much like the old CommonJS Modules/1.0 style. However, it's generally better to return a single thing from a module if possible, rather than a bunch of stuff on an object. We use `module.exports` to accomplish that, and it's mostly good, but it doesn't handle cycles well. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ES Modules: suggestions for improvement
The linked blog post is a very rough cut of where my thoughts are on the subject. Expect changes and cleanup. It does not represent a fully-baked (or even half-baked) idea, but more like a general direction. I expect to clean it up and propose something at least half-baked to this list soon, incorporating some of the feedback that I've gotten from that blog post. On Tue, Jun 26, 2012 at 11:34 AM, Thaddee Tyl wrote: > Another point that I believe Isaac is making is that too much syntax > is likely to confuse developers Developers are very good at getting un-confused by new syntax, and newbies are very good at becoming less new. That's not *much* of a hazard. The bigger hazard is that we can't remove the syntax we add, and historically, humans don't have a perfect track record at expecting consequences, so we should try to reduce additions to the smallest set possible to deliver the more important functionality. In other words, if some % of what we do is a mistake, we halve our mistakes by doing half as much. If we can focus what we do on the things that are very essential to what we need, we can probably beat those odds :) > and allowing certain features, such as > nested modules or `import *`, can be harmful to programmer efficiency > in the long term, if used. Bingo. Favoring the `exports` object instead of `module.exports` was a mistake. Implementing `import *` in Python and Java was a mistake. Copying existing successful systems is good, but we should avoid copying their mistakes if possible. > Isaac, feel free to correct it. Will do. Probably not until after NodeConf early next week. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: optional "function" keyword
So, assuming that these two are valid function expressions that mean roughly the same thing: a: (x) { return "x" } b: function (x) "x" and then you might conclude that this is as well: c: (x) "x" So far, so good, I think. What about these? d: (x) (y) e: (x) (y) { return "z" } f: (x) (y) ("z") g: (x) (y) "z" Leaving aside block lambda TCP freaky-deakiness, I'm not sure mentally how to even parse those. I suppose you could just say that you're not allowed to start an expression-bodied-auto-return function with a (, maybe? I'm not sure. But it is certainly weird and confusing. If e and g both desugar to: h: function (x) { return function (y) { return "z" }} then that could be extremely useful to me. Every ceremonial token has been stripped, leaving only the meaningful bits. It's especially lovely for curry-able functions that are multiply-called: i: curryableFn (a) (b) (c, d) { .. do lots of stuff with a, b, c, and d .. } gogoAsync(args, curryableFn(1)(2)) // calls the resulting cb, a and b pre-set. On Thu, Mar 8, 2012 at 19:35, Kevin Smith wrote: > I think we can use a modification of the Dart technique to parse "=>" > functions: > > On encountering "(" in a context where an expression is acceptable, you can > try to parse it as ( Expression ) or as ( FormalParameterList ). > > Attempt to parse it as a formal parameter list, enqueuing each token > encountered. Either the parameter list will be successfully parsed or not. > > > If a parameter list is successfully parsed, then > > peek at the next token to see if it's a "=>". If it is, then > clear the queued tokens and continue parsing as normal. > If it's not a "=>", then put the queued tokens back into the token > stream and restart parsing from the original "(", this time as > an expression. > > otherwise, if we fail to parse the parameter list, then > > put the queued tokens back into the token stream and restart > parsing from the original "(", this time as an expression. > > Lemma: The "lookahead" token stream that we queue while attempting to parse > ( FormalParameterList ) will be identical to the token stream that we would > have queued if we had attempted to parse ( Expression ). > > Thanks, > kevin > > > On Thu, Mar 8, 2012 at 4:28 PM, Kevin Smith wrote: >> >> Thanks for the clear explanation, Brendan - I think I understand the >> concerns now. And if not, I don't mind looking foolish : ) >> >> I just looked at the code for the Dart parser and it basically queues >> tokens until it finds the matching right paren (recursively counting nested >> parens). It peeks at what comes afterward (like a => or {), and then it >> goes back to the original left paren and resumes parsing, dequeueing the >> already scanned tokens. >> >> Would this technique work for us? The problem that I see is that in JS, >> you can't really tokenize without also parsing (because of the cursed >> lexical ambiguity on '/'). >> >> kevin >> >> >> >> On Thu, Mar 8, 2012 at 2:35 PM, John Tamplin wrote: >>> >>> On Thu, Mar 8, 2012 at 1:08 PM, Brendan Eich wrote: Another which I cited just a few messages back: parsing ( params ) as ( expr ), as any top down parser must until it gets to an arrow or other distinguishing token ({ on same line as ), e.g.), can be considered future-hostile. params should be declarative, but expr must now cover all future declarative syntax, including optional guards. >>> >>> >>> For this particular problem, the Dart parser looks ahead to see if it >>> could be a function declaration. If so, it parses it that way, otherwise it >>> parses as a parenthesized expression. I don't know if this sort of approach >>> would be considered acceptable here or not (it does impose some restrictions >>> on the scanner for n-token lookahead). >>> >>> -- >>> John A. Tamplin >>> Software Engineer (GWT), Google >> >> > > > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: optional "function" keyword
This might be a dumb question: TCP = "this-context preservation"? (Sorry, my brain has that acronym hard-linked to "Transport Control Protocol" and I keep getting confused.) On Wed, Mar 7, 2012 at 13:01, Gavin Barraclough wrote: > But (modulo separate "do" TCP proposal of yesterday) shorter function syntax > is just syntax. No TCP, no lexical |this| in particular. Yes, "functionless function" proposal is just syntax, not a change in semantics. IIUC, reducing the syntax weight of callable-things (whether functions or freaky-deaky lambda things) is a goal in itself. Assuming that we get "() do {}" as the freaky-deeky syntax, would that do the TCP stuff? If so, why not drop block-lambdas, and do the TCP stuff by saying that single-return-expression functions are the ones that do TCP and other freaky stuff? Then you can treat "do {...}" as an expression, somewhat like a block lambda that takes no arguments and is invoked when evaluated. Then you really have three somewhat modest proposals: 1. optional "function". 2. braceless functions that auto-return the completion value of the expression and exhibit TCP freakdeekness. 3. do-expressions blocks that evaluate to their completion value. These three seem to combine to let you do all the good things that block lambdas offer, and are pretty elegant and easy enough to explain to new users, IMHO. The "do" token sort of looks like it means "Do this right here, not in a separate context". It seems like #2 would require the most ironing out. For example: `x = (y) +1` is ambiguous, as is `x = (y)(z)` and many many others. If we use `do {...}` (or something) as an unambiguous "this is an expression", then that could be a nice escape hatch. Ie, `x = (y) do { 1 }` would be akin to `x = tcp_freaky_deeky(function (y) { return 1 })`. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: optional "function" keyword
I'd suggest dropping the Identifier_opt ( FormalParameterList_opt ) [no LineTerminator here] IniitialValue production. Wouldn't that mean that you could have something like this? var allA = list.map(() "a") I think the curly braces are ok here. Hated keywords should be attacked one at a time, imo. On Tue, Mar 6, 2012 at 12:42, Brendan Eich wrote: > Brendan Eich wrote: >> >> ShortFunctionExpression: >> Identifier_opt ( FormalParameterList_opt ) { FunctionBody } >> Identifier_opt ( FormalParameterList_opt ) IniitialValue > > > Let's try that again: > > ShortFunctionExpression: > Identifier_opt ( FormalParameterList_opt ) [no LineTerminator here] { > FunctionBody } > Identifier_opt ( FormalParameterList_opt ) [no LineTerminator here] > IniitialValue > > But of course the second production creates bad ambiguities for all > InitialValue bodies that start with an operator or punctuator that could be > infix as well as prefix: +/-/[ at least. > > More work needed. I may write a strawman up. Encourage me! > > /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: optional "function" keyword
On Tue, Mar 6, 2012 at 12:06, Brendan Eich wrote: >> Yes, an identifier is required. It would not be possible to define an >> unnamed function in this way. > > Why not express an anonymous function, though? Definition != expression. As > usual, an expression *statement* could not start with ( and consist entirely > of a function-keyword-free anonymous function expression. I see. So, you'd be suggesting using: ( args ) { functionBody } as an anonymous function expression, though not a function expression statement? What about these? ;(( args ) { functionBody }) !( args ) { functionBody } Certainly, this is quite nice: myList.forEach((item) { .. }) > Dart has mandatory semicolons to help avoid trouble around the edges of > statements/definitions. > > Candor is new, so no one has deep experience. > > To get further we'd need some brave souls to try this out with a trivial > transpiler, at scale. True that. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: optional "function" keyword
On Tue, Mar 6, 2012 at 10:53, Brendan Eich wrote: > This approach requires a restriction: [no LineTerminator here] between the > ) and the {: > Yes, I did put that in the OP, but it looks like my mail client helpfully wrapped at that point, which is a bit confusing :) Leaving out the f in the "definition" doesn't help, since (a,b,c) is a > comma expression. The requirement is no LineTerminator between the ) and > the {. > Yes, an identifier is required. It would not be possible to define an unnamed function in this way. > Without a leading keyword, it's harder to find the functions. Not > impossible, not saying this is a deal breaker. But it is harder. > Agreed. This was inspired by seeing some code in candor and dart, and getting jealous of their nice terse functions :) However, having not used this style in real programs, it's hard to comment on whether it would continue to be nice, or get annoying. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: optional "function" keyword
On Tue, Mar 6, 2012 at 10:07, Thaddee Tyl wrote: > An interesting property of this syntax is that anonymous functions can > be written this way: > >myList.forEach(λ (item) { doWith(item) }) > > (it can also be `lambda (item) { ... }`) > Yes, any valid function identifier could be used, because it's not actually a keyword. _ (arg) { ... } f (arg) { ... } $ (arg) { ... } ƒ (arg) { ... } ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
optional "function" keyword
A great many letters have been typed regarding the number of letters in the word "function". What if we just made the keyword "function" entirely optional, dart-style? *ShortNamedFunctionDeclaration* *:**Identifier *** *(* * FormalParameterListopt* *) {* *FunctionBody* *}** ShortNamedFunctionExpression* *:**Identifier *** *(* * FormalParameterListopt* *) {* *FunctionBody* *}*Note that the identifier is no longer optional, and that no linebreak is allowed between the parameter list and the body, unlike current function decl/exprs. myList.forEach(x (item) { item += 2 doSomethingElse(item) assert(typeof x === "function") }) // expression, not declaration assert(typeof x === "undefined") // declaration, hoisted assert(typeof doSomethingElse === "function") doSomethingElse (item) { // IIFE, not declaration ;(y (n) { item += n })(Math.random()) assert(typeof y === "undefined") } Is there an obvious case I'm overlooking where this sort of construction would fail? Clearly, you can't put the { on the next line or else it'll be interpreted as an invocation followed by a block, and that could be a significant footgun. But, it's not a *new* footgun, since \n{ is problematic with return anyhow. (I long for a mode where \n{ is always a syntax error.) And, it introduces no new keywords, no syntax that isn't already an error, and no new semantics. I'm eager to see what I missed when you shoot this down :) ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Jan 18 meeting notes
On Wed, Jan 18, 2012 at 17:27, Waldemar Horwat wrote: > Octal constants: > Useful as arguments to chmod. > Proposal for 0o123 (as well as 0b01110). > MarkM: Concerned about 0O123. > Waldemar: Nothing unusul here. We've lived with 36l (meaning 36 long instead > of 361) in Java and C++ for a long time. > Alternative for octal: 8r123 (but then we'd also want 16r123, 2r0101, and > maybe more). > Decided to allow 0o and 0b. Unresolved whether to allow 0O and 0B. > Persistent weak feelings on both sides on the upper case forms. On behalf of Node.js, thank you. This is the right call. FWIW (ie, not much), I'm personally 100% ambivalent about 0O and 0B. 0O is less visually distinctive than 0o, and caps support isn't really necessary. Nr### is not really necessary. Programming happens primarily in bases 2, 8, 10, and 16. (And 64, but that's mostly just for serializing.) If we have 0b, 0o, 0x, and the default base 10, then that's plenty. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Better Native XML Support
I think that requiring a user load a parser to handle XML is perfectly fine. That's the state of the art in most programming languages. On Mon, Jan 16, 2012 at 09:51, David Bruant wrote: > Le 16/01/2012 18:30, Nuno Job a écrit : >> Hi guys, >> >> I would like to make the case for better native XML support in ES5: >> >> This is the most commented open issue on V8: >> http://code.google.com/p/v8/issues/detail?id=235 >> Unfortunately people didn't agree on E4X and this makes the life of >> developers that have to use XML miserable. While XML is not a first >> class citizen in the web it is the preferred interchanged format in >> the enterprise. Developers don't choose to use XML over JSON, they >> sometimes have to use XML. A solution for this would be always better >> if in the language. > Have a look at quasis [1]. It provides what I'd consider to be a more > generic and safer solution to E4X. > You can send feedback to es-discuss@mozilla.org (es5-discuss is usually > reserved to ECMAScript 5 specifically, though most people who are in one > are certainly in both) > > David > > [1] http://wiki.ecmascript.org/doku.php?id=harmony:quasis > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Thoughts on WeakMaps
On Tue, Jun 7, 2011 at 13:59, Mark S. Miller wrote: > There's no where in the standard API of the ES5 built-ins that does this > return-self pattern for purposes of chaining. There are of course JS > libraries, like jQuery, that make pervasive use of chaining. However, > ES-next built-ins should first respect the precedent of the general style of > other built-ins, in order to be least surprising. +1 IMO, the "return the set value" approach seems to make the most sense, since map.set(k, v) is conceptually akin to obj[k] = v. I've always liked that about the HTMLElement.appendChild() function. They're all easy enough to monkey-patch, so this seems a little bikesheddy to me. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Is class syntax really necessary ?
On Mon, May 23, 2011 at 08:51, Brendan Eich wrote: > Class syntax is like a lint brush for such features. If we add it, it will > accrete more semantics (with unambiguous syntax, I hope) over time. This is > just inevitable, in my view. It makes me want to resist classes and look at > smaller and more direct fixes for the two known prototypal hazards. Yes, please! I assume "two known hazards" is referring to your previous email: "subclassed prototype/constructor set-up and super calls." I've been using this pattern in my OOP javascript programs lately: https://github.com/isaacs/inherits/blob/master/inherits.js It works really well, behaves as expected (easy for the author to say, ha, but it doesn't violate instanceof, doesn't call ctors more than once, doesn't clobber already-added prototype properties, etc.) And it's about 10 lines, easy to read and grok. What would make it even nicer, however, with minimal added syntax: 1. Call "super(a, b, c)" instead of "Child.super.call(this, a, b, c)" 2. Maybe Parent.extend(Child) or Child.inherit(Parent) instead of inherits(Child, Parent) 3. Right now, calling parent versions of overridden methods is a painful: "this.constructor.super.prototype.someMethod.call(this)". It'd be nice to use something like "super.someMethod()". ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Short Functions
On Sun, May 22, 2011 at 16:05, Brendan Eich wrote: >> Cutting out many kilobytes of code from JavaScript programs by >> streamlining the single-most commonly-used idiom is hardly frivolous. > > The counterargument, I don't share it but you seem to be focused on > bandwidth, is transfer-encoding compression, gzip. I think you and I agree on this point. Syntax should be judged based on the costs to fingers and brains. In this regard, I think that writing and reading a lot of bytes for a frequent idiom is a bad thing. It's about bandwidth across neurons, not wires. Towards that end, I see a lot of promise in the arrow-function proposal. >> In fact, I'd argue that it should be one of the main goals of this >> list and of TC-39. > > We should have short syntax as a main goal? That hits return too. Indeed it does! That being said, implicit returns are a bit thornier problem for their security implications. > It arguably means block lambdas, since they are more concise > and more expressive. But you demur from them below, so brevity > can't be the top "main goal". I don't think that brevity should be the primary goal of Harmony or es-next, no. But I do think it should be an important consideration. Brevity is not a value in itself. It is a value when the shorter syntax reduces the overall cognitive burden. Code that is easier for humans to think about, tends to also be easier for humans to not mess up. >> The complications have not been very well explored, and are not >> trivial, in my opinion. > > They have been explored in other dynamic languages. They're not that bad. Yes, I guess we are pushing opinions at each other. I'd say that they are that bad. I have experience only with Ruby, not SmallTalk or E. Maybe they're handled better in the other two? >> I am also unconvinced by the "looks like a block" argument. The body >> of a es-current function also "looks like a block", > > No. That's not the relevant comparison. The issue is whether the whole > function-or-block-lambda-expression "looks like a block". That was the point I was trying to make. Having block-lambdas behave like functions is not a hazard. "||" is enough of a differentiator, just like "function ()" is, only with a little less to look at. On Sun, May 22, 2011 at 16:36, Brendan Eich wrote: > To reverse the argument you made: if function body looking like a block > were a source of confusion, we'd already have trouble: I'm not saying it's a source of confusion. I'm saying "this callable thing is dramatically different than that other callable thing" is a bigger hazard than "this curly-brace is dramatically different from that other curly-brace". > But people do not read the return above as returning from function outer. Why > not? Perhaps because callables in JavaScript are all the same, and only ever return out of themselves, never their parent scope. (Of course, ctors called with "new" aren't quite identical to normal functions, because of the implicit "return this". But that is a determined by the call style, not by the function type, and is a much smaller difference.) > More likely, the distinctive function () head syntax before the > body block made it clear. As |arg| would as well. My point there was that "looks like a block" is something of a stretch as an argument for or against anything. Object-literals look like blocks with labelled lines, but we don't seem to have any problems with those (except when we do, of course; qv. every JS repl.) Here's the sort of thing that I'm driving at: function abc (cb) { if (Math.random() < 0.5) cb(100) } function xyz () { abc( {|x| return x } ) return 10 } var p = xyz() The fact that a conditional in abc() can trigger a return in xyz, without transferring control back to the calling function first, seems surprising to me. The situation is further complicated when dealing with asynchronous code. If I'm not mistaken, the following will throw if readyToGo() returns false, yes? function abc (cb) { if (readyToGo()) cb() else setTimeout(cb, 100) } function xyz () { abc( {|x| return x } ) return 10 } var p = xyz() Changes to flow control semantics have subtle implications. Perhaps user-testing will bear out that my taste is in the minority, and that the abuses are lesser or no worse than what we already deal with, I don't know. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Short Functions
On Sat, May 21, 2011 at 23:07, Sami Samhuri wrote: > The semantics have shortcomings though and introducing new syntax to save a > few keystrokes is frivolous. Cutting out many kilobytes of code from JavaScript programs by streamlining the single-most commonly-used idiom is hardly frivolous. In fact, I'd argue that it should be one of the main goals of this list and of TC-39. Adding new semantics to the language seems frivolous to me, if doing so does not solve problems we actually have today. Lambda-blocks, as proposed currently, adds considerable surface area to the language without providing any real value. The complications have not been very well explored, and are not trivial, in my opinion. I am also unconvinced by the "looks like a block" argument. The body of a es-current function also "looks like a block", and no one seems to have a problem with it. Shall we say that "return" in a while loop should be a break, because its body "looks like a function body"? ``` // 1: a current function x = someArray.map(function (x) { return x * x }) // 2: a lambda-block x = someArray.map({ |x| return x * x }) // 3: a current block for (i in x) { return x[i] * x[i] } ``` Who's to say that the lambda-block[2] "looks like a block[3]" any more than the regular function[1]? It's extra syntax above and beyond a current block in either case, and in fact, because it can be wrapped in parens (since it's an expression), it behaves in the language *much* more like a function than like a block. The fact that {||}-style blocks can be passed and assigned to variables makes it remarkably more complicated to reason about them if their return/break/continue semantics are different from existing functions. Because of the fact that they are expressions which can be manipulated, they are more akin to functions than to blocks. The examples from Claus and Allen fill me with trepidation. Please don't do this awful thing. It is the problem with Ruby. We don't need to invent new versions of "for" and "while" in every program. JavaScript's minimal semantic surface is a strength, not a shortcoming. At the very least, the implications of this semantic change need much much more exploration than the other short-function proposals. I realize that it's exciting, but the best footguns typically are. --i ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Short Functions
I very much want short functions. However, the semantics of JavaScript lambdas are so wonderfully simple. Adding a semantically different callable thing is a huge mistake, in my opinion. I'd love to be able to write {|a, b, c| a + b * c } or even (a, b, c) -> { a + b * c } or #(a, b, c) { a + b * c } instead of function (a, b, c) { return a + b * c } but I really don't want to replace our existing simple semantics. I see a lot of the discussions of short function syntax seeming to imply ruby-block semantics, with the "return returns from the parent" idea. It would be great to separate those two concerns. They are very different. One is sugar, the other is a much more radical change to the way the language works, which I'm not altogether convinced is a good or useful thing. --i ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Function Syntax
As always, very well put, Douglas. On Tue, May 10, 2011 at 16:53, Douglas Crockford wrote: > ECMAScript has a large set of problems. I think that the fact that 'function' > has eight letters is at the bottom of the priority list. And yet, I am open to > the possibility of introducing new syntactic sugar to the language to make > the expression of functions more elegant. > > I look at ECMAScript as serving four groups: > > 1. The beginners for whom the language was designed. > 2. The web developers who owe their livelihoods to the language. > 3. The scientists who will use the language for greatness. > 4. Language designers and critics. I think that there is a very subtle way in which Ruby's blocks are perceived, largely because they involve less ceremony than JavaScript's functions. Making the expression of functions more elegant will go a long way towards making newcomers grok their importance and power, as well as a lot of typing (and visual clutter) for those of us in the second group. > Some of the proposals and wishes for new syntax are alarming, in that they > appear to be increasing the problem set, rather than reducing it. For > example, > the language has a confusion between blocks and object literals. Any new > syntax > should reduce or eliminate this confusion, not amplify it. +1. > I want to make the language easier to beginners to learn, streamlining the > syntax, replacing automatic semicolon insertion with statements that are > by design semicolon free. Some of us are already writing JavaScript this way :) The newline elision thing is unnecessarily persnickety, though. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: arrow syntax unnecessary and the idea that "function" is too long
On Tue, May 10, 2011 at 16:22, Oliver Hunt wrote: > \ is a much more common lambda symbol in many languages, and i'm not sure > what the ambiguity would be in \{...} or \(...){...}. \(a,b,c) { a + b * c } That's cute. > I'm also really not happy with the concept of minor variances in syntax > having such dramatic impact the language semantics. All the fiddling with > |this| dramatically increases the complexity of the language, it doesn't > simplify it. I completely agree. It think any short-form function syntax should have the exact same semantics as the existing long-form. We've got .bind(obj). That's enough. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: arrow syntax unnecessary and the idea that "function" is too long
I wrote PHP full time for years. -> can get pretty aggravating. # is 50% shorter, and doesn't use the same fingers that type the (). ()-> is a lot of right-hand-dancing. That being said, it does look pretty nice, and we're all just going to set our editors to do that for us anyhow, right? On Sat, May 7, 2011 at 20:52, Faisal Vali wrote: >> "Kyle Simpson" >> Date: Sat, 7 May 2011 21:58:32 -0500 >> Subject: Re: arrow syntax unnecessary and the idea that "function" is too >> long > > > >> With all due respect, Brendan's personal tastes on what kind of code he >> likes to write is not enough. >> It has to be something that is likely to find wide spread support among the >> JavaScript masses. >> > > Since the arrow syntax assailants have been quite vocal on this list, > lest they be construed as representative of the javascript masses, I > would like to voice a strong endorsement for pursuing and exploring > the arrow syntax further - and I do this as a simple javascript > hobbyist who uses javascript (and JQuery, for lack of the perfect > library) extensively to automate tasks on windows (via htas) and to > write RIAs. > > With all due respect to Mr. Simpson's personal tastes, I find the > aesthetics of the arrow-syntax far more consistent with javascript's > C-based-syntactic roots than the preprocessor-tainted '#' - but I > also recognize that my personal aesthetic tastes are just that. > Anyway, I hope that enough general users share my aesthetic and > usability preference (short syntax for functionally well behaved and > intuitive lambdas with closure capability) that the arrow syntax is > given some serious thought and not dismissed because of this thread. > > Thanks! > > Faisal Vali > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: arrow syntax unnecessary and the idea that "function" is too long
It has been my experience that professional JavaScripters will cheer *any* idea that shortens the spelling of "function" and "return" :) Brendan has said that 8 characters for "function" is at least 6 too many. I think it's probably at least 7 too many. But it'd be a shame to remove the character-count-tax only to introduce a twisting-wrist-tax. I'd prefer something closer to the middle of (most) keyboards than -> or {|. #() is pretty nice, actually. When I suggested "doing away with blocks", I of course was not referring to structures where the block is relevant, such a function bodies, if/else, try/catch/finally, or loops. I was talking about having a bare unadorned block in JavaScript. These are relevant in C, where you have block-scope, but in JavaScript have only made it trickier to know whether something is supposed to be an Object-literal or a block with labelled lines. For example: return { foo: "bar" } // vs return { foo: "bar" } On Sat, May 7, 2011 at 14:39, Claus Reinke wrote: > function bodies extend as far as possible ** I see. So, a function body would be just like an if-block or loop body. One full statement, or a block. There is precedent for that in the rest of the language. So, then, this case: x = function () y; z would be: x = function () { return y }; z am I understanding that correctly? --i ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: arrow syntax unnecessary and the idea that "function" is too long
For what it's worth, I'm a *huge* fan of Ruby's {|-style blocks. Also, it's worth noting that "do...done" seems to be a bit more popular in Ruby programs that I've seen. I'm not a fan of the fact that these blocks have different behavior than "regular" functions and methods, but that's a qualm for a different mailing list, and I'm not a rubyist anyhow :) Consider this: w = (x)->y || z That code is not obvious at all. Which of these would it be? 1: w = function (x) { return y } || z 2: w = function (x) { return y || z } It seems to me that there must be some sort of delineation around the function start and end. I agree that "function ... return" is way too many characters to write and read for such a fundamental bit of syntax. This style is quite clear and readable: w = {|x| y || z} w = {|x| y} || z However, that's pretty awful to type. Perhaps even worse than ->. Maybe {(x) y || z} might be better? Of course, that would break blocks that start with parenthesized sequence blocks, but is that really a concern? Blocks in JS are useless, can't we just do away with them? On Sat, May 7, 2011 at 10:04, Peter Michaux wrote: > On Sat, May 7, 2011 at 9:56 AM, Thaddee Tyl wrote: > >> JavaScript is still seen as a badly object-oriented programming >> language by those who still think it is java with a weird syntax. > > I think that concpetion has declined a lot as rich clients have forced > people to become better acquainted with JavaScript and a lot more has > been written on the language. > >> I do >> hope it grows to be known as an outstanding functional programming >> language. > > JavaScript won't ever be known as a outstanding functional programming > language until it has proper tail calls. This would give the language > new capabilities it doesn't have now. > > Peter > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Automatic Semicolon Insertion: value vs cost; predictability andcontrol; alternatives
On Tue, Apr 19, 2011 at 11:53, Jorge wrote: >> Which minifiers? > I don't know, the ones that make "web apps burn in hell if they are missing > semicolons". Until someone can point to an actual minifier that's actually affected by this, I think the whole "minification requires semicolons" argument is baseless fud. Not trying to impugn you specifically. It takes a lot of work to un-believe something that "everybody knows" :) ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Automatic Semicolon Insertion: value vs cost; predictabilityandcontrol; alternatives
On Tue, Apr 19, 2011 at 11:02, Garrett Smith wrote: > On 4/19/11, Brendan Eich wrote: > I don't mean to annoy by repeating the same things, but here goes: Is > `()` Grouping Operator or Arguments? Is `[]` ArrayLiteral or Property > Accessor? Or do these cases depend on the preceding token? They depend on the preceding token, *and* they cause a preceding \n to be elided. That is the problem with JavaScript's statement termination rules with respect to lines that start with +, /, *, -, (, or [. > Now concatenate a.js and b.js and you have: > var MyWidget = function(){ > this.name = "mike"; > }(function() {}); That error isn't caused by ASI. Disabling ASI won't prevent that error. That error is caused by the lack of ASI. It's caused by the \n being elided when the next line starts with a (. >> So any statement of the form "... ASI changes program behavior WRT >> unrestricted productions is bigger problem" is simply misstated. >> > See above. ASI didn't change the program behavior. ASI didn't happen in that example. Newline elision changed the program behavior. --i ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Automatic Semicolon Insertion: value vs cost; predictability andcontrol; alternatives
On Tue, Apr 19, 2011 at 09:57, Jorge wrote: >> Most web apps will burn in hell if they are missing semicolons when you >> minify them. > > Indeed, for some minifiers it's a must. Which minifiers? Closure, yuicompressor, jsmin, packer, and uglify all handle ASI without so much as a complaint. In fact, with YUICompressor and JSMin, at least, when you omit semicolons, you end up with more easily debuggable minified code, since the line numbers in stack traces are actually helpful. (No "line 1, char 82,343" to deal with.) > These minifiers avoid (understandably) the hassle/expensiveness of building a > parse tree and rely on (clever!) tricks that in turn require the programmer > to put every semicolon in the source text, as if post-ASI, explicitly. I don't believe that "those minifiers" actually get much use. They're hideously broken, and there is a huge selection of competent minifiers that do actually minify JavaScript properly. --i ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Automatic Semicolon Insertion: value vs cost; predictabilityandcontrol; alternatives
On Mon, Apr 18, 2011 at 22:52, Garrett Smith wrote: > On 4/18/11, Claus Reinke wrote: >>> The only places where semicolons are ever used in the Node.js package >>> manager are in the 'for' loops headers and at the *beginning* of the lines >>> that would be interpreted incorrectly because of the lack of the semicolon >>> at the end of the *previous* line - for example see: >>> https://github.com/isaacs/npm/blob/master/lib/utils/read-json.js#L320-L336 >>> >>> There are no semicolons at the end of lines *at all*. npm author here. > If you can think it, there is a porn for it. It's not syntax porn, I assure you. This style is more easily scanned. The important tokens are along the left edge, which forms a straight line with logical and orderly breaks, and those tokens are not overused, so their presence or absence is very noticeable. The right-edge is jagged, and when every line has a ";", the brain tends to filter out their presence, making it hard to notice their absence. Maybe your brain doesn't have the same pattern-matching style as mine, of course. But, willy nilly, I have the brain I do, so I made npm look the way it does, so that it's easier for me to avoid and find bugs with a minimum of friction. This is all to say, relying on ASI is (sometimes) a sane and pragmatic decision, and not difference for difference's sake. > Restricted productions are the most benign cases. How ASI changes > program behavior WRT unrestricted productions is bigger problem. Can you provide examples of the sort of unrestricted productions you're referring to, where unexpected "semicolon insertion" changes program behavior? In my experience, it is the *lack* of ASI that usually causes problems with unrestricted productions. >> In brief, there is no way simply to take away ASI, and any >> attempt to introduce a less troublesome variant of ASI will >> have to offer a way to deal with existing code. >> > The number of developers advocating ASI as a "best practice" can't be > stopped either. Developers using ASI and advocating its use should be taken as a datapoint for our discussion of the language, don't you think? Regardless of whether or not you agree with them, breaking their model drastically will only result in a lower adoption of Harmony/es-next/opt-in-whatever. >> As a coder, you really don't want to add semicolons to >> avoid ASI traps, as in line 232 of your example >> >> ;["dependencies", "devDependencies"].forEach(function (d) { Yes. I've never started a line with [ with the intent of it being a property access. I do sometimes start a new line with ( for a function call, if the list of arguments is long, but it's a practice I'd gladly change in exchange for saner statement ending rules. > Why do I want to have to worry about what might have been omitted? No, > I want to worry about what the code says. I consider a statement > terminator to be just that; when I read it, I see end of statement. > don't want to read beginning of statement preceeded by empty > statement. In that case, what the code "says" is exactly the same, whether the semicolon is on the next line or not. There is nothing fundamental or essential about ; being a "terminator" rather than a "separator". In fact, that's what it actually is in EcmaScript - a statement separator. (Likewise in sh/bash/zsh, Perl, Ruby, Erlang, and many others.) In Java, PHP, C, and C++, it is a terminator. This isn't c-devel or java-devel, it's es-devel. The "use superasi" pragma would effectively make [ and ( treated a bit like restricted productions, in that a line break before them *always* terminates the statement. I'm not sold on this idea, necessarily, but I think it's important to consider options other than how to remove ASI from the language. > Exactly. Multiline comments add extra problems. How so? --i ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Automatic Semicolon Insertion: value vs cost; predictability andcontrol; alternatives
On Mon, Apr 18, 2011 at 12:22, Brendan Eich wrote: > I agree, but in a friendly spirit suggest typing ; is a tax too, however much > lesser. True, I overstated. It *is* a keyboard tax. But (at least in my experience) I tend to type code in a moment, and then read it for the rest of my life. I'd gladly pay a keyboard tax that lowered the cognitive burden of maintaining code. > Some expressions that do not involve calling, assigning, or otherwise > potentially having effects (declaring, where the declaration is a misplaced > function expression) still may have effects (e.g. getters). > Your suggestion seems to be to avoid analysis and warn based only the syntax > of the expression that follows on a separate line a bare, unterminated > return. I think I agree, but I wanted to call this choice out for more > discussion. > Indentation, yay. Necessary in your view, or could you just ignore everything > except the separation by a line terminator? Thinking about this a bit more, I think maybe this whole suggestion is a bad idea. Forget I said anything. Significant linebreaks are one thing, but significant indentation is deeply problematic. Maybe the solution is a way to make return's expression non-optional? If you want to return nothing, then you'd `return undefined` or `return null`. In any event, I think spending a lot of effort trying to figure out the best way to remove ASI from the language is an unprofitable path. That energy would be better spent trying to figure out how best to remove just the problems with the current ASI implementation, and not throw out the baby with the bathwater. --i ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Automatic Semicolon Insertion: value vs cost; predictability andcontrol; alternatives
On Mon, Apr 18, 2011 at 11:05, Brendan Eich wrote: > Given the primary problem is not ASI but its absence where users expect it > due to mistakenly believing a newline is significant, one could argue the fix > is not to ban ASI and tax everyone with writing lots of insignificant > semicolons (in some opt-in mode hardly anyone would use, which would only > crud up implementations' parser state spaces). > > One could argue instead that we need *more* newline signfiicance. Yes. This is the sanest thing I've read in this thread. How about this? "use superasi" Result: 1. /\n\s*[\[\(+*\/-]/ is a syntax error. (Or should it silently do ASI here? Not sure.) 2. /;\s+\n/ is a syntax error. (No extraneous semicolons.) This would enforce proper use of ASI, and turn off the problems where statements are confusingly not ended by \n. (Starting a line with a "." should still be allowed, since that is not otherwise a valid construction, and thus not easily confused.) Arguments for: 1. Mostly backwards compatible, except in the case which everyone seems to agree is a language defect. 2. Prevents the wtfs that are cited as being due to ASI. 3. Encourages developers to know the language they're using. Arguments against: 1. Ew. There aren't semicolons there. --i ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Fwd: Automatic Semicolon Insertion: value vs cost; predictability andcontrol; alternatives
On Mon, Apr 18, 2011 at 05:42, Jorge wrote: > I understand that it would be quite interesting to get a warning/error in > this case: > a= b > (c= d)(); > ...only that there's no ASI in this case ! Jorge touches on the reason why the whole debate about ASI is a bit misguided, in my opinion. The "} or \n ended a statement" ASI doesn't usually bite, except in the case of restricted productions, where it looks like it wouldn't end. return { a : 1 }; This is a situation that's extremely easy to avoid with a simple and easily lint-able rule: "return\n is an error". However, is it reasonable to treat strike this ASI with the same hammer? b.on("click", function () { alert("hi!") }); I don't think so. No reasonable JavaScripter would be surprised that the alert line ended at the }. Furthermore, it is not the existence of ASI, but rather the lack of it that causes problems even more frequently than the restricted productions issue. var a = 1; var b = 2; var c = { foo : "bar" } [a, b].forEach(alert); // cannot call method 'forEach' of undefined A "disable ASI" pragma will not catch this error. No ASI occurred! In my years writing JavaScript, I can count on one finger the number of times that restricted production ASI has bitten me. I immediately abandoned the Allman style in favor of a BSD-KNF brace-goes-with-the-start-thing style, and all was well with the world. This no longer looked strange to me: return { foo : "bar" }; I can also count on one finger the number of restricted productions where this is an issue: throw will issue a syntax error, since the expression is not optional, and named continue/break are very rare. However, the "non-ASI" error above (where there is a \n followed by a [, (, +, etc) bites a *lot*, and is almost impossible to see when parsing the code with human eyes and brains. The proliferation of ; is not a keyboard-tax. It is an eyeball/brain-tax. "Why complain about semicolons? You don't even see them." That's why. Because I want to see the relevant parts of my code. If you put them on every line, and worse, at the jagged-right edge of the line, The options are to either: * use a lint step in your development process to catch these issues (and it's gonna have to be a pretty clever linter to know you didn't mean to do that) * adopt a style where such things jump out at you because they look wrong (as I have done with npm's leading semicolon/comma style), or * Be Very Careful about using array literals and parenthesized constructions. I find linters to be somewhat unpleasant housepets, and thus do not keep them in my own home, though I of course respect their place when contributing to others' projects, and I have found that Being Very Careful is not sustainable on teams of 1 or more humans. Any approach that does not handle the "non-ASI error" case is not a solution. Every time a warning prints about something that was intended, the value of warnings is reduced. That's a bad idea. In the onclick ASI example above, printing a warning about the ASI in that code would be worse than useless. If we are going to build a less wicked language, and the idea of a warning-generating pragma seems wise, then we ought to make every warning as relevant as possible, and not just support backwards-compatibility, but also do our best to support the intent of those using the language. Here's a few situations where (in my opinion) warnings would be useful: 1. Restricted production followed by \n and an expression which is not a method or function call, assignment, or function declaration. // these would warn: return { a: b } / return 10 + 5 2. Expression followed by \n and a +, (, [, -, *, / at the same indention level. // this would warn: x = y (c + d).print() // this would not: chain ( [some, long, thing] , [the, next, chain, link] , cb ) --i ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss