I think Jeremy probably has one of the highest programming-chops-to-arrogance ratios among today's top programmers. It was a tweet, he said what he needed to say. He's been more than willing on HN to step in and explain Coffeescript to critics and offer helpful critiques of competing frameworks (well, in the context of Backbone).
But he writes coffeescript so unlike you he's a "top programmer". except for times when he writes javascript which probably would be when hes drunk or for whatever reasons his IQ has dropped.
99% of the popular people out there are just above average enough to make useful projects for those lesser experienced. Most truly talented people are not very well known, they're busy hacking on v8, the kernel etc. Tools for average programming just get more of a spotlight. Is Express complex? no, people just use it, is coffeescript complex? no, is boostrap complex? no..
Like anything else in life there is front facing people that are generally good at marketing and would use other people's hard work to build technically inferior stuff on and be famous for. Not necessary a bad thing. The truly talented most of the time choose to go unnoticed. And there is always trolls like you who I don't know how they find the time to ship code ;p
Perhaps you are being too hard on yourself. The majority (more than half) of the well known programmers truly are "superstars". It's all very subjective, though. Where is the standard for complexity or even cleverness? How is it different than simply being esoteric. Maybe I am personally fascinated with regular expressions and after much study, can belt out a half page of parse and extract 'magic' that would make the uninitiated shake their head and crown me a genius. But to me, it's simply assembling larger ideas from smaller ideas.
Personally, I would say that a truly talented programmer is simply someone who is very capable in mathematics and can produce a working and extendable program in a reasonable amount of time, that does something new and useful. This criteria alone leaves a ton of people out, you know!
There are certainly truly epic people out there that are well known, but hell me and Jeremy have many more followers than the guy who wrote openssl along with people like Mike Pall who could out-code most of us any day, it's a weird thing, but you're average programmer isn't concerned about lower level things like that, so they simply don't care. There are of course exceptions to this, people like Carmack or Linus, but still, you see my point.
I think it has already been proven that there is no obvious correlation between being capable in mathematics and being a talented programmer. Thats so 1950's
Not a direct coorelation, but there is certainly a dependence on being capable in mathematics. A math wizard does not make a good programmer, but one cannot be hopelessly average in math and be a talented programmer.
Actually it really depends on what math skills you talk about. Is it really the material you are taught and can apply to software that brings a lot ? The ability to solve problems ? The culture of correctness ?
The common ground between math and programming is the requirement of a very good capacity to manipulate abstract concepts in a defined frame of known validity. But it pretty much stops here. In mathematics, you define all your abstracts concepts and frame of validity, in programming, you are given a (very shaky and detailed) frame of validity on which you build up abstract concepts.
The ones that are good in approaching the discipline through the study of details to build up stuff that will work on top of it will make the developers. The ones that needs a strong and well defined frame for their work, for it brings a much more powerful ground and enable to reach very high levels of abstraction, will feel more comfortable on mathematics.
No wonder why those that can combines both of those approaches can yield stunning results.
How is it different than simply being esoteric. Maybe I am personally fascinated with regular expressions and after much study, can belt out a half page of parse and extract 'magic' that would make the uninitiated shake their head and crown me a genius.
Sounds interesting, tell me more.
Personally, I would say that a truly talented programmer is simply someone who is very capable in mathematics and can produce a working and extendable program in a reasonable amount of time, that does something new and useful.
I would also say a criterion is that he really understands abstraction and how to get more from less. Ie think of how John Carmack creates abstraction which is just right for the problem (and in C at that). Or think about the metalinguistic paradigm in programming (or OOP used right, for that matter). Or how JQuery (and these days Coffeescript) makes client-side web code clean and accessible to everyone, without the previous Javascript hacks and DOM-spaghetti. An average programmer just plods along and hacks out a solution in a linear manner, a great programmer will traverse levels of abstraction to not only solve the problem but also shine a light at it from a superior perspective.
jQuery nor coffeescript really imply "clean" client-side code, in fact I would argue that most uses of jQuery are the opposite if you compare communities like mootools. As far as coffeescript goes you still need a good sense of structure like regular javascript, nothing new there really.
jQuery makes the DOM so dang accessible that people use it as their data, which is completely backwards. Fortunately stuff like backbone has brought back some sanity.
That sounds like a really accurate statistic. So what's your metric for this? Besides the obvious law that low-level code is the only grounds for elite coding, I mean.
umm no haha, I'm certainly amongst the average. Trust me writing parsers is very trivial, I've written many. Thinking you're a good programmer is perhaps the most naive thing you can do
I know its trivial once demystified specially using parser generators. But language design isn't though. Anyways i think your a pretty decent programmer.
they're certainly above average but even Ryan himself is humble enough to admit he's not amazing, I dont recall what his exact words were. I think it was on google+, he was talking about how he works with such brilliant people (which are lesser known), but yeah overall node's popularity is largely because it attracts more average people to the scene, vs things like erlang or haskell which are fantastic but attract a lot less attention.
This is also why I dont do conferences, I dont want to be known for going around promoting things (like crock), sure I'll blog about features added once and a while but other than that I want the projects to speak for themselves. Eventually if I can gain enough knowledge then sure being well known is neat since you can leverage it to hopefully expose better projects, but there's no end to what you can learn in this industry.
Whether he's right is another question. But if you don't like his decision you can use the Coco (https://github.com/satyr/coco) fork which fixes it by introducing := for nonlocal assignment.
The reasoning basically seems to be "if you misuse this feature (i.e. have top-level symbols), you'll get bugs (like the OP discovered), therefore don't misuse this feature (i.e. keep your top scopes clean), and therefore you won't get bugs, and therefore it's not a problem with CoffeeScript".
It shouldn't take a lot of thought to see why this is a somewhat user-hostile, passive-aggressive approach for a language. If something is ill-advised, the language should actively steer you away from it, not dissuade you with subtle bugs a few thousand lines of code down the road.
I think this scheme would be more workable if sigils or similar conventions of some kind were mandatory for top-level symbols. Then it would be much harder to accidentally wander into this problem. The language he seems to be drawing inspiration from, Ruby, does do this.
Like everything in languages (or APIs), there's a tradeoff here. By making scoping automatic, and (hopefully) forbidding shadowing, you can make the language conceptually simpler. Think of it as making variables be "referentially transparent" in terms of their lexical scope. Everywhere you see "A" within a given lexical scope -- you know that "A" always refers to the same thing. In a language with "var" and with shadowing, "A" could mean many different things within any given lexical scope, and you have to hunt for the nearest declaration to tell which one it is.
On the downside, you have what Armin describes: If you happen to try to use the same name for two different things within the same lexical scope, it won't work.
Since it's always the case that you are able to choose a more descriptive name for your variable, and gain clearer code by it, I think it's very much a tradeoff worth making.
You haven't said anything new to me here; I took all this for granted and it isn't what I'm criticizing. You haven't actually addressed my summary of the apparent reasoning for why accidental assignments to top-level symbols isn't a pathology of CoffeeScript. The bit I'm criticizing is the failure mode of "if you happen to try to use the same name for two different things within the same lexical scope, it won't work".
I see. The reason I can't address your "failure mode" with an explicit suggestion is because it isn't a failure mode in CoffeeScript: If you assign a new value to a variable in an inner scope, the variable now has a new value. If you're thinking "I want to use the same name for two different variables" ... the answer is: choose a different (better) name for one of them.
But perhaps I'm still not getting at the answer you're looking for here...
You keep stating and restating how and why CoffeeScript doesn't support shadowing of symbols via lexical scoping.
That's not what I'm criticizing. Lexical shadowing is not what I'm advocating. I think your choice is fine in so far as it goes. It has its logic.
What I am criticizing is how it can fail. The top scope is different, quantitatively and qualitatively, from almost all nested scopes. It's much larger, and spread lexically over a larger area. If you have a team of developers, it will be modified concurrently. No one developer necessarily knows the full set of symbols defined in the top scope while they are writing an individual procedure.
And thus the problem: a developer thinks they've chosen a "different (better) name" for a some variable, but in fact they've chosen one that a different developer also thought was a "different (better) name", only one of them is in a lexically enclosing scope. This problem isn't likely to occur on the level of nested procedures or nested blocks, because the definitions would be visually close. But it's much more likely to happen when one of the symbols is defined in the top scope. Here, the definition could be many hundreds or thousands of lines away. It may even be in a separate commit, waiting to be merged, such that there's no way for either developer to know without closely reviewing every change.
And this is the criticism: the failure mode for this inadvertent reuse of a variable name is subtle bugs, as what one developer thought was a global symbol turns out to be modified and acquire strange values through unexpected codeflow, almost like the VM was corrupted and memory was behaving unreliably.
The qualitative difference of the top scope in situations like this is the reason why I suggested sigils or somesuch to disambiguate those scenarios. Perhaps top-level symbols can't be reassigned from nested scopes unless you use '$' as a prefix to their name; a visual shorthand that you are definitely not creating a new local symbol.
The reason I summarized your argument in the way I did is because your argument against this failure mode seems to be "don't create top scopes with lots of symbols". That's a fine argument (or rather, exhortation), but it isn't a realistic one. If the language is problematic with lots of symbols in the top scope, it should be unpleasant to use with lots of symbols in the top scope. And the unpleasantness shouldn't come from subtle bugs (the passive aggressiveness I mentioned); it should come from awkward and ugly sigils, or some other intrinsic way of discouraging those styles.
barrkel, I think you should create a new programming language with more sensible scoping than CoffeeScript, so that developers can create bug-free code while working in parallel on thousand-line codebases without close reviews. I would start by using "$" as a sigil to prevent top-level variables from being reassigned in nested scopes. It would be a visual shorthand that indicates that you are definitely not creating a new local symbol. This would prevent developers from needing to know the full set of symbols in the top scope. In fact, by eliminating the inadvertent reuse of variable names, you would eliminate the failure mode whereby what one developer thought to be a global symbol actually turned out to be modified. Eliminating this unexpected codeflow would be tantamount to eliminating memory corruptions in VM.
You should definitely go down this track. It would be a massive achievement.
I think you think you're being sarcastic. But I do actually work for a developer tools company, and I implement language features on a continuous basis. I implemented anonymous methods - closures - for Delphi, a task that involves no small amount of scope wrangling; and FWIW, Delphi almost certainly has a larger userbase than CoffeeScript, albeit one with greyer hairs. While my specialism is in statically typed, compiled languages, issues around lexically nested scope are pretty much the same as in dynamic languages.
If you want to have a constructive conversation, you could try dialing back the snark, and addressing my arguments directly.
Ok, I'll dial back the snark and just be blunt. I think all your concerns about CoffeeScript are hypothetical exaggerations. I don't think you've written much CoffeeScript at all, and I suspect that if you did, you'd quickly see that your concerns are overblown. In theory, you could have thousands of lines in a single file, and two commits from a separate branch could cause an undetectable accidental naming collision. In practice, this rarely happens. Files tend to be smaller, merge changes do to tend to get scrutiny, and name collisions often have fairly obvious symptoms once you run your tests on the code.
I think if you have good practices - small files, scrutiny of changes, unit tests - you can make any language work. The test of a language comes in how it bites you when you stray. So to be blunt, I think your defense is irrelevant.
The problem with mandatory conventions is that they represent a different kind of user hostility--you're not trusting the developer to make his own decisions about variable names.
To give an example, many CoffeeScript programmers do follow simple naming conventions to call out top-level variables, such as CamelCase for classes or ALL_CAPS for constants. When you follow these conventions, it's pretty easy to avoid naming collisions.
In certain cases, though, you want a top-level variable to be lowercase, perhaps for stylistic reasons. If your files are relatively small, it's pretty easy to check for naming collisions when you introduce top-level variables after the fact, so a developer might decide that the risk is acceptable, especially if there is good test coverage.
Another kind of user hostility is to optimize for safety at all costs. I don't think any scoping mechanism totally eliminates the possibility of bugs, but some schemes do err on the side of safety over convenience. There's nothing wrong with trading off convenience for safety, but, on the other hand, you can make judgment calls that convenience and/or simplicity of the scoping model outweigh the risk of naming collisions.
Obviously, I like CoffeeScript, so I think Jeremy's made the correct tradeoffs. All languages work a little different--JavaScript, CoffeeScript, Python2, Python3, and Ruby all have different rules--and none of them are perfect in all situations. In all of the languages, though, it's reasonably straightforward to write correct code once you adopt general good practices--be careful with your names, and understand the language's approach to scoping.
I really don't understand why this isn't being fixed: doesn't global by default break encapsulation?
I'm probably missing something, but this is the main reason I haven't tried coffeescript yet.
Just to be completely clear, variables are only at top level scope if you declare them at top-level scope. The variables "x" below are completely encapsulated within f1 and f2. The variables at top-level scope are intentional in the code below--I really do intend f1, f2, and how_many_times_functions_have_been_called to refer to the same entity throughout the file.
how_many_times_functions_have_been_called = 0
f1 = ->
how_many_times_functions_have_been_called += 1 # refers to top-level scope
console.log x # undefined
x = 1
console.log x # 1
f2 = ->
f1() # refers to f1 at top-level scope
how_many_times_functions_have_been_called += 1 # refers to lop-level scope
console.log x # undefined
x = 2
console.log x # 2
f1() # you can call f1, it's at top-level scope
f2() # you can call f2, it's at top-level scope
console.log how_many_times_functions_have_been_called # 3, refers to top-level scope
console.log x? # false, x does not exist at top_level scope
Yes, I probably wasn't very clear: what I meant is that a programmer writing a function somewhere in a program must have a complete knowledge of the scope where the function is and will be in the future, including changes in global variables exposed by the interpreter/browser.
In the end I would find me forced to add a prefix to all the variables in order to avoid collisions, just like I would be forced to do, if the language only had a single global scope.
This behaviour seems quite unreasonable to me, but I haven't been able to find explanations about it, other than it's expected behaviour.
Fortunately, what you're describing isn't how it works.
CoffeeScript will automatically declare all variables in the nearest lexical scope it can find. The top-level scope in CoffeeScript isn't global -- it's the top of the file. You don't have to know anything about what values may or may not exist in global scope at any given moment ... all you have to know is what variables are visible in your function's enclosing scopes, just within the file you're working in.
Everyday there seems to be a new post on HN, complete with inflammatory headline, criticizing Coffeescript in someway because it doesn't work in the exact way the author expected.
There are lots of people throwing in their $0.02 on how the language should work without having joined the mailing list or seen any discussions on the thought process behind its features.
I'm not saying the suggestion made isn't reasonable, but I can understand glib replies like this from the author that don't make too much effort to explain his stance more than 140 characters.
In fairness, Armin (the author the blog post) did engage Jeremy (the author of coffeescript) on this issue over twitter. I wish that he would allow comments on his blog. I also wish that he could engage the broader CS community in a proper forum before dissing the language and/or creating a fork of the language. He's overreacting. This whole blog post apparently started because he had a naming collision with "log" in one of his programs. CS does have a mailing list, but most of the action happens via github issues.
> I wish that he would allow comments on his blog.
Why? Hackernews and reddit exist and everybody is free to send me a mail or contact me on twitter. This way I do not have to moderate any comments or deal with spam.
> I also wish that he could engage the broader CS community in a proper forum before dissing the language and/or creating a fork of the language.
And do what? Duplicating an issue that is already there? Commenting on a dead issue? The author has expressed his unwillingness to deal with this issue so why should I reopen the issue there?
> He's overreacting.
How am I? I wrote a very short blog post about why I think the scoping is bad and how it caused me problems. Many people asked me on Twitter why I think the scoping does not work as good as it should and since I only have 140 characters to explain stuff there I wrote it to my blog. How else should I communicate that?
> CS does have a mailing list, but most of the action happens via github issues.
There is an issue about this topic from a year ago which was closed and the author does not want this to be changed. I am okay with that, a language needs leadership. That does not mean however that other people should not know about this issue when they design the next programming language.
I wish that you would allow comments on your blog, so that folks following your twitter link would be able to see both sides of the issue, but I obviously understand your spam issues, which is why I said "wish" and not "should".
I wish that you would engage the CS community on this topic without the sole agenda of getting this fixed. It's true that the issue was put to rest a while ago, but the decision wasn't made in a vacuum--there was consensus involved. I think it's a little unfair to say that Jeremy "has expressed his unwillingness to deal with this issue"; that makes it sound like he was dismissing you or dismissing further debate on this, when in fact he just told you what had already been decided.
When I say you're overreacting on this issue, it's just my opinion, so don't get too worked up about it. You had a bug. "Log" means two things. IMHO you don't need to fork coffeescript; that would be a gross overreaction, but YMMV.
You are not doing anything wrong by taking the time to write up your opinion in a blog--if I implied that in any way, it was not out of malice; it was just imprecise writing on my part.
For what it's worth, thanks for that detailed article. I've just used Coffeescript for a large-ish WebGL project and had no idea of that behaviour. I got freaked out when I got to the bottom of that first fragment and saw log vs log.
I'm going to keep using Coffeescript, I love it. Maybe this kind of scoping isn't the best decision for modularity and teamwork, but on reflection at least the rules are simple and consistent enough for a single programmer to keep in mind.
Blog posts about (and against) CoffeeScript features are great, as is discussion on HN, as is discussion on the issues pages.
In addition, nothing in CoffeeScript is set in stone -- because every script compiled with every version of CoffeeScript is compatible with every other version, we're much more comfortable making changes to the language than we otherwise would be. If you can make the case that this change is a good idea, we'll definitely make it. So feel free to comment on the old issue or open a new one if you wish.
> because every script compiled with every version of CoffeeScript is compatible with every other version, we're much more comfortable making changes to the language than we otherwise would be.
This attitude concerns me. I can't just say "oh, that's CoffeeScript 1.0 stuff, just trash it, the JS still works". I still have to update the CoffeeScript to upgrade the version. There's no less risk in breaking backwards compat with CoffeeScript than any other language.
Sorry -- that was supposed to be a friendly tweet-sized response. The discussion about this "feature" is always good to have, especially because it's one of the most rightfully controversial changes that CoffeeScript makes to JavaScript semantics.
There are dozens of lengthy conversations about this in the CoffeeScript issues, if you'd like to take a deeper look.
Of course, it's kind of socially acceptable to get wrong because a lot of language designers didn't think it through and used the same operator for both binding and reassigning a variable (i.e. '=').
How arrogant! You'd think he'd step back for a second and consider the suggestion, but it sounds like he's on autopilot.