

Coffeescript 1.9.0 contains a backwards incompatible change - davidbanham
http://blog.davidbanham.com/articles/coffeescript-psa/

======
jashkenas
CoffeeScript doesn't follow "Semantic" versioning. Most projects that claim to
follow "Semantic" versioning actually don't.

Take, for example, the other news at the top of the front page, Io.js 1.3.0 —
a minor version bump that should include _zero_ breaking changes to the public
API.

And yet, 1.3.0 "broke" the way that urls are resolved with regards to trailing
slashes:
[https://github.com/iojs/io.js/pull/278](https://github.com/iojs/io.js/pull/278)

If you follow SemVer — and I don't think that Io.js should, or have to pretend
to — this _must_ be yanked, and re-released as Io.js 2.0.

Ironically, the behavior being complained about in this post relates to how
CoffeeScript decides to name internal compiler variables. This is not
something that has ever been part of the public API — and is something we can
(and might) change at any point. We've changed it in the past.

Breaking changes in your API are a good thing — when the new way is better
than the old. But this isn't one of them.

For more on SemVer, and why you should resist giving in to its fascist attempt
at world version domination, see:
[https://gist.github.com/jashkenas/cbd2b088e20279ae2c8e](https://gist.github.com/jashkenas/cbd2b088e20279ae2c8e)

I get that SemVer is an attempt to address dependency pain — but it's woefully
inadequate, reductive and dangerous. We can do better.

~~~
Touche
The point of the article is that NPM uses semver. If you disagree with semver
you should use a different package manager.

> And yet, 1.3.0 "broke" the way that urls are resolved with regards to
> trailing slashes:
> [https://github.com/iojs/io.js/pull/278](https://github.com/iojs/io.js/pull/278)

Can you link to documentation of the old way? The way I understand it is that
they fixed a bug. If they broke a documented API I would agree with you,
should be a major version bump.

Lastly there's a gigantic difference between breaking code because you made a
mistake and breaking code because you don't give a shit and romanticize
version numbers.

~~~
jashkenas
Here's the documentation of the public API:

[http://nodejs.org/api/url.html#url_url_resolve_from_to](http://nodejs.org/api/url.html#url_url_resolve_from_to)

They changed the way that it resolves:

    
    
        url.resolve('/path/to/file', '.')
    

... to include a trailing slash when it returns the new URL to your code.

No big deal, but it breaks apps. It's not backwards compatible. SemVer is not
about feature-vs-bugfix. It's about _changes_ to documented behavior. This is
a breaking change, so it _must_ be Io.js 2.0.

If you think I'm making a mountain out of a molehill here — I am. This change
isn't a big deal. Io.js shouldn't have to bump to 2.0 to deal with it. But
pretending to follow "Semantic" Versioning when you're not is just silly.

Death to tyranny, right?

~~~
Touche
You might have a point here, they should bump to 2.0. Let's see why they
didn't do so.

------
Zr40
According to [1], the previously accepted syntax was never documented as being
valid. That means that code affected by this change was relying on
undocumented behavior.

[1]:
[https://github.com/jashkenas/coffeescript/issues/3819](https://github.com/jashkenas/coffeescript/issues/3819)

~~~
xtrumanx
Well that adds a much needed bit of context to the conversation. Someone
decided to use undocumented behaviour in a production application and got bit.
Worded as such it doesn't make Coffeescript to sound so ridiculous.

~~~
jrochkind1
"decided" implies they knew they were using undocumented behavior and chose to
do it anyway. The use of the word 'undocumented' also implies that unless a
behavior is explicitly mentioned in the documentation, it should be considered
'private' and 'subject to change' \-- also not a safe assumption with many
projects, whose documentation is far from completely covering all intended
behavior.

~~~
xtrumanx
Sorry, I'm not a Coffeescript user so I'm familiar with its idioms. I looked
up the Coffeescript website and it says:

> As a shortcut for this.property, you can use @property.

It also said that since March 2010 according to the Internet Archive's Wayback
Machine. Why did this fellow decide to use `property` instead? I don't know
but I wouldn't hold this specific situation against the Coffeescript team. But
that's just like my opinion, man.

~~~
davidbanham
Completely agree that the particular bit of code shouldn't have been relying
on that functionality.

A totally reasonable response would be "Oh, sorry, I had no idea people were
using that in that manner."

Fine, fair enough.

But! It was known that people were relying on that behaviour and it was
mentioned in the changelog. That is a big point in favour of Jeremy as a
package maintainer. Not only does he know how his code should be used, but he
has an understanding of how people are using it in the wild. That's wonderful
and praiseworthy.

Where I get grumpy is that this was seen as a significant enough event to
mention to the humans who happen to be reading the changelog. Yet, it wasn't
deemed appropriate to tell all of the computers that are installing
dependencies about it.

------
epidemian
What's up with these kind of childish slander of OSS projects being upvoted to
the top?

Anyway, funnily enough, this change was not only rectified on CoffeeScript
1.9.1, but it was also a change that only affected code that relied of the
names of compiler-generated variables.

    
    
      foo = (@bar) ->
        # Bad: "bar" is not declared anywhere
        console.log bar
        # Good: the parameter is "@bar", so that should be used instead
        console.log @bar
    

Relying on a "bar" variable existing inside that function body is no different
from relying on an "_i" variable exiting inside a look like:

    
    
      for a in arr
        console.log "the index is", _i
    

... which, BTW, would also break if upgrading to CoffeeScript 1.9, because the
compiler-generated iterator variable would now be called "i" :)

Update: i misinterpreted something. What was rectified in CoffeeScript 1.9.1
was the addition of an "_at_" prefix for the generated parameters of
`(@something) ->` functions, which broke Angular's dependency injection
mechanism when using it like `(@$someAngularThingy) ->`. You still can't
access the auto-generated "bar" parameter in the first snippet. If you access
a "bar" variable inside that function, the auto-generated parameter is then
named "bar1", which is the Right Thing to do :D

~~~
ufo
Did the first example at least give a warning or did it silently succeed?

~~~
epidemian
Alas, no, the compiler does not warn about that. I don't know if it should
though, as accessing a "bar" variable inside that function might be legal if
bar was assigned as global variable, which the CoffeeScript compiler has no
way to track.

~~~
ufo
Ah, thats unfortunate... I do think giving a warning should be possible
though. Coffescript has some weird variable scoping rules but the scopes are
still static so the compiler you should be able to detect if you are accessing
one of the compiler-generated internal variables.

------
davej
It's interesting to note that the current #1 story on Hacker News is io.js
1.3.0.

And the current #1 comment on that story is wondering what the reason is
behind the version jumps in quick succession without much in the way of new
features (1.0.3->1.0.4->1.2.0->1.3.0).

These two stories nicely sum-up the romantic vs semantic versioning debate.

------
alessioalex
The author of CoffeeScript also created Underscore. He did the exact same
thing there:
[https://github.com/jashkenas/underscore/issues/1805](https://github.com/jashkenas/underscore/issues/1805)

So bottom line: if you use CoffeeScript, Underscore of Backbone.js pay close
attention to upgrades.

------
bmh_ca
I was burned by this as well.

The breaking code would look like this:

```

a = (@arg) ->

    
    
       console.log(arg)  # Used to print arg.
    
       # Now needs to be:
    
       console.log(@arg)
    

```

The problem was particularly exacerbated on our end by using `coffeeify`,
which includes the latest CoffeeScript - so one could not easily pin to a
particular version of CoffeeScript (i.e. 1.8.x).

This brings into question, for me, the decision making process for
CoffeeScript. So the migration begins.

Contrast, lodash which just had a bunch of backwards-incompatible changes.
They changed its version from 2.x to 3.x, so we all head a heads up. Lots of
things broke, but we knew to look for them.

~~~
untog
Why were you referencing a variable that doesn't exist? Your code shows a bug
in CoffeeScript, which was fixed.

------
kevincennis
But, like...

Why did you update to a new version of Coffeescript and not know about this
bug before it made it to your production environment?

I agree that Coffeescript should probably just use semver. But they don't, and
you have no control over that.

What you _do_ have control over is when you update your dependencies and
whether or not you validate releases before deploying to production.

It seems a little disingenuous to act like this is entirely Coffeescript's
fault.

~~~
lmm
npm has a substantial amount of valuable automated tooling that assumes
semver. It is the standard of that community.

~~~
kevincennis
Yeah, I completely understand that. I work on big Node apps every day.

But anyone who's had an app in production for very long learns pretty quickly
that you you use "1.8.0", not "^1.8.0" if you don't want things to break.

------
thinkpad20
I'm not sure why this was made into a blog post and put on HN. This kind of
thing seems more suited to a bug tracker. Mistakes happen sometimes; report
them and let the developer community take a look at them. That's the advantage
of open-source.

------
michaelmior
I think even when using semver, you should lock down your dependencies (e.g.
npm shrinkwrap). My approach is often to periodically delete npm-
shrinkwrap.json, Gemfile.lock, composer.lock, etc. and then install updated
dependencies and thoroughly test things.

You still get the benefit of a reasonably loose specification of what versions
of dependencies you expect to be compatible with, but additional security in
knowing that you won't be surprised by unexpected breaking changes.

------
flipp3r
Even if it would use semver, you should not auto-install or update packeges in
your production environment without having it tested first. Semver is just a
promise other people are making, and in production you shouldn't rely on that
IMO.

------
coderzach
Maybe semver needs a fourth "Vanity" version, that you can increment when it
"feels right". i.e. Backbone 1.43.3.1

------
gerjomarty
The problem we had when trying to push semantic versioning of our app to the
rest of the business internally was mostly the fact that breaking changes
necessitated a change in the major version, but the business and marketing
side wanted control of when a major version could be released.

I can see their point, because going from, for example, 1.1.0 to 2.0.0, a user
might well expect lots of new features, or at least a significant UI change,
and not just "it looks and does the same except for one or two breaking
changes".

The compromise was to have an architect's vanity number at the front of the
Semantic version, so VANITY.MAJOR.MINOR.PATCH

~~~
jrochkind1
The other option is simply _not releasing breaking changes_ until you are
ready for a 'major' release with new features. Sometimes this can be a pain,
but every choice here can be a pain, the question is how much pain, and for
whom (consumers, developers.... marketting people).

------
bmh100
I understand the pain of having changes that should be innocent leading to
breaks in production. What is your strategy around testing for upgrades like
this? JavaScript is not my area of expertise.

~~~
striking
Oftentimes, you'll already have written tests to make sure your logic works.
Otherwise, you might just run your app in a test environment and make sure it
doesn't immediately crash. (Because that's what CoffeeScript would do in this
case, as far as I know.) Pretty standard stuff across the industry.

------
yoshuaw
This reminds me of this excellent ode to exotic versioning schemes --
[http://sentimentalversioning.org/](http://sentimentalversioning.org/)

~~~
yoshuaw
From the backbone archives (linked in the article):
[https://github.com/jashkenas/backbone/issues/2888#issuecomme...](https://github.com/jashkenas/backbone/issues/2888#issuecomment-29076249)

------
artursapek
I've written a big project in Coffeescript in the past and it was
teremendously more fun than it would have been to write in vanilla JS. However
with ES6 around the corner I think it would be a mistake to start any projects
in Coffeescript now. We just adopted ES6-to-5 translation via Babel[1] at work
and people are really excited about it.

[1] [http://babeljs.io/](http://babeljs.io/)

------
meesterdude
ES6 is pretty good - I'd rather write with that than coffeescript.

------
kibwen
I'm interested in this story because Rust is a language that _does_ intend to
follow semver, which AFAIK is something that has never been attempted by a
programming language. As of yet it hasn't been forced to bump versions thanks
to clauses 4 and 9 of the semver spec, but that will change as of the 1.0.0
release on May 15. Before that date I highly anticipate a document from the
Rust developers that will attempt to lay out precisely what does and does not
constitute a "breaking change" in order to avert the situation that has arisen
here.

~~~
davidbanham
Or they'll just pull on their grown-up trousers and bump the damn major every
time there's a breaking change.

------
iamdanfox
I've greatly enjoyed writing CoffeeScript, but am concerned that over the long
term, it will fall behind javascript in terms of feature support.

The [Babel][1] transpiler (formerly 6to5) and tooling like Facebook's
typechecker, [flow][2] have large teams and a rapid pace of development.

I don't want to miss out on cool features like generators, let/const, etc just
for CoffeeScript's lovely bracket-less code.

[1]: [https://babeljs.io/](https://babeljs.io/) [2]:
[http://flowtype.org/](http://flowtype.org/)

~~~
feedjoelpie
Ditto. I don't think the CoffeeScript philosophy as it stands will ever have
it keeping up with the pace of JavaScript proper at this point. Within the
next year, I think our company will be migrating back to the land of curly
braces. The charms of CoffeeScript just aren't worth missing out on all the
great stuff coming to JavaScript as of late.

------
slindsey
People can do whatever they want with their version numbers. But I like to
follow the Apache Version Numbering
([http://apr.apache.org/versioning.html](http://apr.apache.org/versioning.html))
where backward compatibility is inherent in the number. Any change that breaks
something requires a major version number change.

------
bryanlarsen
Hint: if a project claims to be following semver and the major number is
small, the project either is very young, not being actively maintained or
they're probably not actually following semver. All three are red flags.
Library maintainers shouldn't be afraid to bump the major.

