-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CS2 Discussion: Question: Is conflating null and undefined a feature of CoffeeScript? #4945
Comments
From @lydell on 2016-10-19 07:55 In VimFx (~5k lines of CoffeeScript), But for It would be nice to hear @jashkenas’ wisdom on this as well. Is parameter defaults behaving different in CoffeeScript compared to ES a relief or a point of confusion for new CoffeeScript users? What about already experienced users? |
From @triskweline on 2016-10-19 08:01 While Conflate for existential Conflate for default arguments => I'd much rather have the cleaner Javascript output. Note that "The compiled output is readable" is also a CS feature, it says so right on the homepage! In the PR discussion, I get @lydell saying that he doesn't care about the difference, got into the habbit of using |
From @jashkenas on 2016-10-19 14:13 It's tricky. Having two slightly different values for nothing is absolutely a mistake in JavaScript, and it's something we tried to smooth over a bit in CoffeeScript my making But getting the clean output for the 2.X branch is also a desirable outcome. I'd say that it's tragic, but go for the clean output for 2.0, and we'll live with the inconsistency. |
From @GeoffreyBooth on 2016-10-20 15:06 We should be keeping track of breaking changes somewhere. A wiki page on the main repo? A wiki page here? A markdown file in the project? Part of index.html in the project? |
From @lydell on 2016-10-20 15:19 Let’s start with a wiki page on the main repo. |
From @GeoffreyBooth on 2016-10-21 05:32 Wiki page here. I’ve updated #4311 to reflect this decision (assuming we’re going with ES syntax, at least for now). |
From @connec on 2016-10-21 17:37 Paraphrased from #4311 (wall of text incoming): Full disclosure: I'm in the same bucket as lydell in that I've tended to use I would rather lose ES2015's defaults and keep existence checks consistent. I really don't like the idea of defaults behaving differently to ?, ?=, etc. (though ?() gives precedent for that...). To illustrate a problem with this, currently you can use argument defaults to make values in functions 'safe' for existence checks, i.e. a default is as good as an existence check. action = (options = {}) ->
# We can safely call options.whatever here, since we know it's not undefined or null
options.whatever Admittedly this is also an issue with ES2015, but it's one that CoffeeScript solves by treating null and undefined as non-existent values, for existence checks and defaults. My issue isn't so much about allowing If clean output is such a desirable outcome, why not just skip CS and use ES2015? I appreciate that's a bit melodramatic, and CS adds much more value than just Finally, I do feel we're being a bit flippant about changing CS semantics when there's no compatibility reason to do so, particularly when there's so much value in a release of CoffeeScript that fixes what's broken (classes) without breaking lots of backwards compatibility. |
From @jashkenas on 2016-10-21 17:43
I agree — but I think that's basically the whole point of the current plan for "CoffeeScript 2". CoffeeScript 1 can continue to be the nice little well-tended garden that it has been ... but the point of CS2 is to embrace as much of modern JS as we can, even if that means losing some nice things that we've previously enjoyed. |
From @GeoffreyBooth on 2016-10-21 18:02 @connec does have a point about classes: some people might want to limit their breaking changes to “just” classes, to get the interoperability with ES classes that they need, and could care less about any other changes CS2 brings to the table. For such people it will be annoying to have to choose between 1.x’s lack of As much as I hate to say it, we could release the classes fix as an off-by-default flag on 1.x, so that people have a way to opt-in to that breaking change without any of the others. The only other interoperability concern that 2 was planning to address was tagged template literals, but those can be implemented in 1.x too without breaking changes (whereas regular ES template literals, by contrast, need to be 2-only). This might even be a way to thread the needle with regard to how we want to deal with classes in 2: the maximum-compatibility version, basically what @connec is working on in #4330, could be the opt-in ES-compatibility classes for 1.x; and a new implementation of classes that more closely tracks the ES spec could be what’s in 2. This sounds like a lot of work, and I’m not saying I recommend it, but it’s an option. |
From @jashkenas on 2016-10-21 18:14 Just for the record: I think that sort of muddled approach is the exact wrong way to go. It's already complicated, and the clarity of — CoffeeScript 1 is the CoffeeScript you know. — is critical. If you add a flag for classes in 1, next you're going to be adding a flag for async, and then for some sort of advanced module feature, and then another flag for ES destructuring ... and so on. |
From @GeoffreyBooth on 2016-10-21 18:54 I agree, but I wanted to throw it out there as an option. I suppose someone could always make a fork of CS1 plus #4330, if they really really wanted only the new classes but nothing else. I guess the bigger question when it comes to “brought as close to modern JavaScript as possible” is, how close? We could disallow splats in function parameters that aren’t the final parameter, the way ES2015 does; that would certainly have made my PR far easier to implement. But that seemed like a pointless restriction to impose on CoffeeScript, even if that’s what ES requires. I think we basically agreed in the other thread that prettier output alone is rarely good enough to justify a breaking change; but conforming to ES spec for parameter default values has a benefit beyond streamlined output, in that CoffeeScript would then behave more like ES2015 for people familiar with ES. It’s like if we add support for For the record, I think it’s worth conforming to ES on this issue at least. But I understand the complaint. Read up the thread of #4311 and you’ll see it took me some convincing as to which “old” features we were going to preserve, even if it meant outputting lots of extra JavaScript. |
From @connec on 2016-10-21 19:43 Apologies for another wall of text, but I'm an avid fan of CoffeeScript as it is today, and appreciate the decisions that were made in its design, particularly wrt. executable class bodies and conflating I feel like there's a balance of features that would satisfy people on both sides. There are plenty of features with compelling reasons to switch to ES2015:
The main one here is definitely Once they are taken care of, there are other things where the main benefit is cleaner output at the cost of backwards compatibility within CS. Full class compilation, implementing splats, and default arguments would only be 'simple' if CS' semantics are changed (e.g. no more executable class bodies, no more rest before args, defaults not overriding null). These are certainly more controversial. My fundamental problem with adopting changes in this category is they take away features from the language without adding anything. I do understand that reducing friction with ES will make CS a more compelling choice for people looking for something 'like JS, but prettier', but certainly in these cases (executable class bodies, rest args, and defaults) there would be very few surprises for users that couldn't be summed up in some short sentences:
|
From @GeoffreyBooth on 2016-10-22 18:31 I don’t feel strongly about this either way. The code is written for either implementation. Perhaps we need more opinions? |
From @leonexis on 2016-10-22 20:13 There is a lot to be considered here. I'm in the "ES but prettier" camp. I've fought and lost hours many times with CS1 mainly due to some of the fundamental differences between CS and ES. The only reasons why I stuck with it mainly included class support and easier-to-read code. I've looked at changing to ES2015+ because it now implements many of the features I wanted, but it is still ugly as sin. Readability is currently winning out for me, but nothing would make this developer happier than have some more cohesiveness between CS and ES. A lot of my lost time dealt with treating null and undefined the same in CS where I expected it to be treated differently coming from ES. For features that ES just didn't have (like the existential operator), I didn't care that it treated null and undefined the same, because that was not an ES feature, but something awesome and unique added in CS. In short, if I'm writing something that looks like ES in CS, it should act like, and preferably output, ES. For example, if I use a rest argument like In any case, all you guys are doing an amazing job. These are just my two cents. |
From @GeoffreyBooth on 2016-10-26 05:32 Update: I’ve merged in #4311 (arrow functions, including default parameters) following the ES spec, where a parameter default value is applied for |
From @leonexis on 2016-10-26 17:02 I like siding on ES compatibility for this stage of CS2, but I also agree with needing more input. The commercial projects I'm involved with only account for about a hundred thousand lines of code split between browser and server software, and I can't release any of that. Thats pretty small compared to the rest of the CS community. It would be interesting to get feedback from the Atom.io developers since the Atom editor is mostly written in CoffeeScript. This is also a critical time since according to recent commit logs, Atom is converting some CoffeeScript to JavaScript. I've always used them as an example of a large scale project written in CS and would hate to loose them as a big supporter of CS. |
From @emptist on 2016-11-01 00:52 I believe those who seeking for similarity in CoffeeScript will finally turn to use pure JavaScript itself. |
From @danielbayley on 2016-11-26 15:19
Agreed!
Having written a bunch of @atom packages and being a big CS fan myself, I definitely feel the same way… Penny for your thoughts @lee-dohm? |
From @JavascriptIsMagic on 2016-11-27 16:26 I have been writing my code in coffeescript at work for quite some time now, though I'm afraid most of it is closed source like leonexis. There where two things that really drew me to coffeescript: I had some pressure at work to switch over to ES after the => was added, but the lack of the existential operator is actually what won me an argument to stay on coffeescript with my coworkers instead of migrating over to es6. That being said, if we do need compatability with only undefined in the case of default perimeters, why not allow the ?= to be used in their place when we want the old behavior of conflating null?
I am really sad to see that the ES spec got it wrong in my opinion, because one of the points of default parameters and destructuring assignment with defaults in my mind is to grantee that you won't be getting a TypeError if you try to use the . operator on those variables. I know this does not solve the backwards compatibility with old code bases, but I would really miss the null and undefined conflation here! |
From @leonexis on 2016-11-27 16:44 I really love the option proposed by @JavascriptIsMagic. If it doesn't conflict with anything else internally, I think using |
From @GeoffreyBooth on 2016-11-27 21:11
|
From @vendethiel on 2016-11-27 22:05 I'm not sure it it should be This one's a hard one. Even if we go that route, people will have to update all their |
From @vendethiel on 2016-11-27 22:06 (As I'm thinking about it, writing a tool that reports every instance to change should actually be doable) |
From @connec on 2016-11-27 23:11 Parroting myself a bit, but I still feel like the best choice would be to change default arguments to behave how they did before. They add a bit of verbosity to the compiled output when checking default arguments, but have a consistent definition of existence. |
From @JavascriptIsMagic on 2016-11-28 03:18 One thing I notice is that if we output to es6 default function parameters and destructuring that: In CS1 Are function defaults going to have the same behavior as destructuring default assignments? One question I would have is should all assignment operators be valid? Just making If we only exclusively use ES6 syntax for default function parameters and for destructuring, I am very likely to stop using these features almost entirely because I will not be able to avoid risking a |
From @GeoffreyBooth on 2016-11-28 04:14 To keep things on track, for now at least we’ve made the decision that when it comes to CS2, we’re following ES semantics when it comes to features that ES has adopted from CoffeeScript. It’s too confusing for people coming from ES for function default parameters to behave one way in ES and a different way in CS. Ditto for destructuring when that is implemented. Not only is CoffeeScript “just JavaScript,” but one of the other core principles is that we generate concise, readable output; and compiling ES features one-to-one should be the expected behavior. That doesn’t mean we can’t extend ES. In the CS2 version of fat arrow functions, we allow |
From @jashkenas on 2016-11-28 17:41 I think for V2, in this case, we should just follow the ES |
From @vendethiel on 2016-11-28 18:28 I'm not sure I'd call it a new operator. |
From @jashkenas on 2016-11-28 18:32 The problem is with object destructuring ... simple arguments would be alright, but introducing a separate form of equality into objects would get real ugly, real fast:
Gross! |
From @GeoffreyBooth on 2016-11-30 23:00 I think the decision has been made for now: when it comes to function default parameters and destructuring, CoffeeScript 2 will conform to ES semantics and output idiomatic ES. If people want to propose sugar like |
From @carlsmith on 2017-01-28 05:29
I disagree. In an ideal type system, there should be two Null type values. I would name them There's a conceptual distinction between An API could specify that a value is either an instance of Some expressions, like With function invocations, arguments that are To try and offer a concrete use case, when you use an interactive interpreter, the value of any expression is automatically printed, so you can just enter >>> print(1 + 1)
2
none
>>> When you interactively use an API where Admittedly, there are no super compelling use cases, but the conceptual distinction is still important enough to matter. I think Eich had the right idea about this. We obviously don't want |
From @jashkenas on 2017-01-30 16:15 Of course, I disagree — and the fact that you had to explain your intended philosophy of the distinction between Just because you've learned and internalized your preferred distinction between "intentional nothing" and "accidental nothing" doesn't mean that all of the other users, library writers and coworkers in your hypothetical language have done the same. Besides, we already have
|
From @carlsmith on 2017-01-30 17:50 It's not really a hypothetical language. I was trying to generalise for all type systems. JavaScript has I didn't really get the point about having Not being able to distinguish between a function explicitly returning If there's only one Null type value, and you had To be honest, I've had to take tons of morphine every day for months, so should probably not being debating language design with a language designer. Thanks for your patience mate. |
From @rattrayalex on 2017-01-30 19:38 Wow, hope you're okay man! |
From @carlsmith on 2017-01-30 22:53 Cheers dude. I'm cool. My disc went in my spine. I'm ok if I take my meds, but they make it difficult to focus. It's annoying when I want to code, but it's not the end of the world. I hope you're all well. Thanks for all the work you're doing. It's good to see 2.0.0 coming together. Thanks again man. |
From @GeoffreyBooth on 2016-10-19 07:15
In CoffeeScript 1.x,
null
andundefined
are often interchangeable:if foo?
returns false whetherfoo
isnull
or whetherfoo
isundefined
.((a = 1) -> a)(null)
and((a = 1) -> a)(undefined)
both return1
.In ES2015, at least regarding default function parameters,
null
andundefined
are not interchangeable:(function (a = 1) { return a; })(null)
returnsnull
.(function (a = 1) { return a; })(undefined)
returns1
.This has sparked a discussion in the PR where I’m trying to implement arrow functions (and by extension, ES-style default parameters) for CoffeeScript 2. Basically, if we want to preserve the current behavior where the default value is applied when a parameter is null or undefined, we need to keep the current generated output:
So if we want output like this:
Then we have to break backward compatibility and go with ES’ implementation of default parameter values applying only when the parameter is undefined, not null or undefined. We can’t do both (the default value and the
null
if block) because the default value could be a function call, for examplef = (a = b()) -> a
.CoffeeScript 2 was going to break backward compatibility anyway, but we want to break as little as possible. Is this
null
/undefined
interchangeability something that people value in CoffeeScript 1.x, or would you not miss it if it went away? How important is it that the generated JavaScript for a feature like default function parameters be as ES-like as possible?The text was updated successfully, but these errors were encountered: