Live data from Hacker News

A Case Against Using CoffeeScript

ryanflorence.com

71–80 of 142 posts

Re: A Case Against Using CoffeeScript

#71
post #26

Earlier quoted context omitted.

You're right - but I'd argue that the difference is just in default behavior, as you touched on in your edit. Ruby procs are bound to their lexical scope, and implicitly include self as a part of that scope. The function still has to be aware of some scope to run, though. (I didn't know about assigning self in instance_eval, though - that makes me all kinds of happy!) What I meant to convey is that every language tha…

What do you mean by Lua leaving the caller to explicitly specify? Are you referring to earlier versions of Lua that used the explicit ^ upvalue sigil? Lua 5.1 (and 5.2) functions close over all local variables (including the implicit “self” introduced by function definitions with colon syntax), with the innermost ones first and no explicit upvalue sigil, much like Scheme.

Nah; regular old Lua 5.1. The colon syntax is just syntactic sugar -- self isn't actually bound.

function Foo:Bar(baz) is the same as Foo.Bar = function(self, baz); invoking Foo:Bar("rebar") is sugar for Foo.Bar(Foo, "rebar"). self is never bound - it's just passed in (explicitly, via . syntax, or implicitly, vs : syntax). In all cases, the caller is always specified.

You can pass Foo.Bar around (as it's a function reference), but if you have something like:

    Foo = {}
    function Foo:Bar(baz)
        print(baz)
    end

    local baz = Foo.Bar
Then baz has no binding information to Foo; defining the function with the : syntax is just syntactic sugar. To invoke, you would have to call:

    baz(Foo, "woohoo")
Just calling

    baz("woohoo")
populates self with "woohoo", and the bar parameter would be nil, demonstrating that there is no contextual binding to the function itself.

Re: A Case Against Using CoffeeScript

#72
post #66

Earlier quoted context omitted.

Dishes is an object, a dish is an object. I know what I'm doing :) dishes = { ryansPlate: { dirty: true }, yourPlate: { dirty: false }, hisPlate: { dirty: false } } Now go into the debugger, find the _ref, and then add a break point, inspect it, and you'll see. Or if it was just JS, you wouldn't have to mess with _ref, you'd just put in a break point right where you were last looking at the code wondering "what kind…

Sure, and here's the issue: At the point you do plate.dirty plate === "ryansPlate" In CoffeeScript the construct for foo of bar Iterates through the KEYS of bar in turn, assigning them to foo...NOT the values To be more specific, it iterates through PROPERTY NAMES. Per the JS spec, property names are always strings (you can't use objects...but you know this I'm just being thorough.) In your example, you do plate.dirt…

I do find it interesting that you didn't go "Oh, if he's got an object, he just missed `key`" so I could argue you likewise not as proficient as you could be :P

Re: A Case Against Using CoffeeScript

#73
post #5

Earlier quoted context omitted.

I dunno. I think that a lot of that is just a matter of developer maturity and code discipline. If you can't recognize a code smell when you're writing code, the problem is probably that you aren't mature enough as a developer, not that the language is bad for allowing it. I don't think that most seasoned developers would look at that 160-column list comprehension, say "okay, that works!" and move on to the next task…

I've seen terrible JS, but I've seen much worse CS. Most programmers have relatively no sense of organization, and when unleashed with CS create things far more nasty than their JS counterparts. nasty: https://github.com/jashkenas/coffee-script/blob/master/src/r... nasty: https://github.com/jashkenas/coffee-script/blob/master/src/o... nasty: https://github.com/jashkenas/coffee-script/blob/master/src/c... sexy: https:…

I've seen terrible assembly but I've seen much worse C. Most programmers have relatively no sense of organization, and when unleashed with C create things far more nasty than their assembly counterparts.

nasty: https://github.com/mirrors/gcc/blob/master/gcc/c-family/c-co...

nasty: https://github.com/mirrors/gcc/blob/master/gcc/c-family/c-le...

But you get the idea. I'm merely pointing out that compilers are tricky and complicated beasts. And especially in the rewriter CS has to jump through hoops to disambiguate.

Re: A Case Against Using CoffeeScript

#74
post #71

Earlier quoted context omitted.

What do you mean by Lua leaving the caller to explicitly specify? Are you referring to earlier versions of Lua that used the explicit ^ upvalue sigil? Lua 5.1 (and 5.2) functions close over all local variables (including the implicit “self” introduced by function definitions with colon syntax), with the innermost ones first and no explicit upvalue sigil, much like Scheme.

Nah; regular old Lua 5.1. The colon syntax is just syntactic sugar -- self isn't actually bound. function Foo:Bar(baz) is the same as Foo.Bar = function(self, baz); invoking Foo:Bar("rebar") is sugar for Foo.Bar(Foo, "rebar"). self is never bound - it's just passed in (explicitly, via . syntax, or implicitly, vs : syntax). In all cases, the caller is always specified. You can pass Foo.Bar around (as it's a function r…

What do you mean “isn't actually bound”? The function being defined using colon syntax doesn't close over self, since it's a parameter—but functions defined within that function will close over the self parameter, since it's a local from an enclosing scope:

    foo = { x = 3 }
    function foo:bar(baz)
        return function(thud)
            return thud + baz + self.x
        end
    end

    womble = foo:bar(4)
    womble(7) --> 14
Python I believe also closes over self as a variable, and Ruby has similar behavior for local procs, even though « self » is a special form in Ruby.

This is in distinct contrast to JavaScript, where the value of the special form « this » goes nuts inside closures because it's attached to the function:

    foo = { x: 3 };
    foo.bar = function(baz) {
        return function(thud) {
            return thud + baz + this.x;
        };
    };

    womble = foo.bar(4);
    womble(7) # --> NaN
So in what way are you placing Lua and JavaScript together, and Python and Ruby together?

[slightly rearranged for clarity]

Re: A Case Against Using CoffeeScript

#75
post #13

Earlier quoted context omitted.

First-class functions have the `this` problem in every language, and the fat arrow is very nice syntactic sugar for what you have to do anyway Not true. JavaScript's `this` binding is absolutely not the only way to do it. In Ruby: class Foo def hello return proc { self } end end puts Foo.new.hello.call #=> # In Python: class Foo(object): def hello(self): def zoo(): return self return zoo zoo = Foo().hello() print(zoo…

So, this is really interesting... JavaScript is forced to make the pessimal choice of only ever having dynamic-bound "this", because of that favorite whipping boy ... prototypal inheritance. If JavaScript had a notion of a class (even as a constructor function + prototype) definition, then it would be possible to tag methods with the correct instance reference, as in Ruby and in Python. Unfortunately, because the sta…

You should look at Lua. Yes, if you want a notion of "self" or "this" with prototypal inheritance, then it must be dynamically bound. However, this does not have to be a burden on, or even be noticeable by, the programmer. Good language design can avoid most of the pitfalls in JavaScript...

Re: A Case Against Using CoffeeScript

#76
post #70

Earlier quoted context omitted.

Dishes is an object, a dish is an object. I know what I'm doing :) dishes = { ryansPlate: { dirty: true }, yourPlate: { dirty: false }, hisPlate: { dirty: false } } Now go into the debugger, find the _ref, and then add a break point, inspect it, and you'll see. Or if it was just JS, you wouldn't have to mess with _ref, you'd just put in a break point right where you were last looking at the code wondering "what kind…

> Go ahead an chalk that up to "Ryan doesn't know CS", if you believe it's any more incriminating than missing any ol' arg in a function signature. Precisely what I intend to do. Everyone makes little logic errors and whatnot, I was just trying to use this as an opportunity to show that people who are, while not necessarily new, but not super experienced...will have a harder time spotting stuff like this in the langu…

Again I say, you should have caught that I missed the `key` every bit as much as I forgot it ;)

Re: A Case Against Using CoffeeScript

#77
I just spent my entire day tracking down a missing "var" that caused a bug only in Internet Explorer. I haven't written any assembly code since college, and I hope to reach a day when I never have to write or maintain native Javascript again.

Re: A Case Against Using CoffeeScript

#78

My code is more readable for me than yours. That’s just how it is. While the JavaScript CoffeeScript compiles looks decent, it’s still not mine. That would change if you practiced reading other peoples' code. When I see my code, I often think, "yeah, I wrote this" because I know how I name things, but other than that, my code looks like everyone else's code. I know this because I based my style on what other people d…

> That would change if you practiced reading other peoples' code.

I'm really active on github, and actually read the source code of a lot of projects instead of reading books, and contribute to a bunch of them too. Quite assuming of you to assume I don't.

My code, since I wrote it, will always be easier to understand because I dealt with every problem--not because of the style.

Re: A Case Against Using CoffeeScript

#79

Earlier quoted context omitted.

> if/when browsers natively support CS. They won't, and source maps are not native support. Check out AMD with RequireJS (make sure you optimize) for your "import" stuff. I haven't incorporated optimization yet for the project, but you can see how it works with my snackJS project http://github.com/rpflorence/snack/tree/amd-coffee/lib

Thanks Ryan. I've looked at the RequireJS/AMD import stuff and it seems really over engineered for what I need. I feel like there is too much declaration going on. For now I think I'll wait to see what else people come up with along these lines.

Well, AMD is essentially a CommonJS format, so this is what "people have come up with" for the browsers until real modules show up :)

http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition

Post reply on HN