jashkenas / coffeescript

Unfancy JavaScript
https://coffeescript.org/
MIT License
16.46k stars 1.98k forks source link

TIMTOWTDIBSCINABTE: Assignment edition #518

Closed TrevorBurnham closed 13 years ago

TrevorBurnham commented 13 years ago

OK, as jashkenas suggested at issue 514, I'm going to be opening some issues on areas where CoffeeScript provides multiple ways of doing things, in hopes of achieving some streamlining. The title stands for There's more than one way to do it, but sometimes consistency is not a bad thing either.

Jeremy isn't going to like this one, but I've got to say it: CoffeeScript's dual assignment, : and =, fixes a problem that no one had. The stated intent of supporting : for all assignment is that it's used for assignment in the object syntax (that is, between curly braces). But there are several semantic differences between the two ({a: 'A'} doesn't have the same scope issues as a: 'A'), as well as difference syntactic affordances ({x += 1} doesn't make sense, while x += 1 does).

I've started using : for all assignment, because it's the recommended CoffeeScript syntax, but I don't think I'll ever get in the habit of using x: + '5' (not to be confused with x:+ 5 and x: +5, which both compile to x = +'5'). As I recall, x +: 5 was supported for a while, but then it was dropped (can't find the issue). But let's face it, nothing done with : will ever be as clear as the += that every programmer is familiar with.

So my position is that JavaScript is right: It makes perfect sense to use one operator, :, for assignment between curly braces, and another operator, =, for assignment elsewhere. That feels totally consistent to me. But I'd like to hear what other folks think.

devongovett commented 13 years ago

+1 to that. I think = is much clearer than : anyway. Maybe I'm just used to it, but it just feels right to use = whereas : is awkward to me. And x: + 5 isn't very intuitive compared with x += 5.

StanAngeloff commented 13 years ago

I don't and never have liked the : + half-operator. It is ugly, error-prone and I haven't used a whitespace sensitive operator before so it feels... bad. I quite like obj: or default, though. I smell irony.

This is one of those discussions... My personal feeling is we should keep the standard assignment operators =, +=, -=, ... and let people decide what to use. I hate Python and the saying only one way to do things. Why?

timbertson commented 13 years ago

I agree with trevor wholeheartedly. another reason I dislike ":" is that it's much harder to spot a missing ":" than a missing "=". very annoying for creating functions, far moreso than other languages that use an actual keyword ("def", "function", etc).

djcsdy commented 13 years ago

I really like the : operator. As soon as I saw it I knew I would like CoffeeScript.

Let’s face it, using = for assignment is wrong, and it always has been wrong. Assignment and equality are fundamentally different things.

The use of = for assignment is possibly the most destructive design decision in the history of programming languages. When a programmer reads the code if (x=5), in his head he says ‘if x equals five’. This sounds correct, despite being horribly wrong. Different things should look different. Different things should be pronounced differently. Every programmer has run into this exact problem multiple times in their career, even after years of experience.

IMHO, of the languages that use a different operator to denote assignment, CoffeeScript has made by far the best choice.

The only disadvantage I can think of is its originality. I don’t know of another language that uses the colon in this way, so it’s unfamiliar. I think this disadvantage is tempered by the fact that it’s pretty obvious what the colon means.

All other languages that I’m aware of either use keywords for assignment, or use one of the following:

I would like to see = removed and replaced with :.

For consistency, I would also like to see +=, -= and friends removed in favour of +:, -:, etc, although I’ll admit they look a bit weird and are difficult to pronounce. It’d be interesting to know why they were removed.

: +, with mandatory whitespace is, IMO, horrendous, because whitespace is invisible and unpronounceable.

zmthy commented 13 years ago

The whitespace is pronounceable. It simply changes the way you read the code. one: + two # reads "plus two" one: +two # reads "positive two"

I'm still not sure where I sit on half operators. The keyword based ones are super, and it follows nicely that the operators can have the same behaviour. It's just those pesky unary operations getting in the way.

I like using them. So ignoring arguments towards other people's confusion, +1 for colons and half assignments.

djcsdy commented 13 years ago

But those two things look very similar despite being completely different. Our brains are wired to match patterns even if those patterns don’t exist. Developers will lump those things together subconsciously even if they consciously know better. Experience tells me that almost everyone will read both of those as ‘plus two’ because, literally, that is what they both say.

Also, it doesn’t work for negatives:

one: - two # reads "minus two"
one: -two #  reads "minus two"

I suppose you could say ‘negative two’ for the second example, but everyone I know says ‘minus’ when they want to specify a negative number. It doesn’t really work for positives either, since ‘plus’ can legitimately be used in place of ‘positive’ (although that’s less common).

Shouldn’t we pre-emptively avoid tying ourselves up in knots, and make sure that different things look and sound as different as possible?

zmthy commented 13 years ago

I always think of the unary minus as "negative".

That said, perhaps we could avoid confusion by making the unary operators only be considered when wrapped in parens? That way one is clearly a different thing. one: + two one: (+two) By the current standard, code like one +two should really compile into one(+two) rather than one + two. So really the ambiguity also exists in parens-less function calls.

djcsdy commented 13 years ago

To me it would make more sense to resolve all the ambiguity by, for every half operator, simply reversing the order of the colon and the half operator:

one +: two
one -: two
one ?: two
one not: two
one or: two
one and: two

etc.

As far as I can see there is no ambiguity for any half-operator using this ordering, although some of the more esoteric combinations read a bit strangely.

It also has the advantage of being consistent with the existential accessor, which is ?. and not .?.

zmthy commented 13 years ago

But now the assignment is far less obvious. With the colon attached to the thing you are assigning to, it's blindingly clear what's going on, and moving the colon away removes this clarity, particularly in line with other assignments. one: two two: three one +: three two: one The half assign doesn't match up with the nature of the other assignments.

jashkenas commented 13 years ago

If you haven't read the previous tickets on this yet, I suggest starting with these two. They have over 70 comments between them:

http://github.com/jashkenas/coffee-script/issues/issue/71 http://github.com/jashkenas/coffee-script/issues/issue/261

I lay out my opinion pretty clearly in those, but to summarize it briefly:

Most of the coffeescript syntax has been designed and evaluated in relation to readability by a person from any background -- not for familiarity for programmers in other languages -- if that were the case, we'd have stuck much more closely to JavaScript. = and == are a personal bugaboo of mine, because I remember very clearly what the stumbling blocks were for an introductory programming class I took. Recursion was a big one, but even before that, variables, assignment, equality, and passing by reference was the first major headache for the class, tripping up some folks for weeks, and causing others to drop the course. Pretend you have nothing but an algebra background, and look at this:

a = 5
b = a
a == 5  # true
b == a  # true
a = 10
b == a  # false

"Huh? But I set b to be equal to a. They have to be the same." Even without the when-do-I-use=-and-when-do-I-use-== question, it's already a bit of a brain-bender. Compare it to the equivalent CoffeeScript:

a: 5
b: a
a is 5  # true
b is a  # true
a: 10
b is a  # false

Taking a step back, this second example seems much more clear to me -- you aren't asserting propositions about algebraic equality -- you're labeling numbers with names, and moving the label later on.

Anyhow, that's just the rationale for the current behavior. I'm glad the reaction to it is mixed, but if there's a strong consensus for going one way or the other, I'd be glad to. The current behavior of making : interchangeable with = is just pragmatic -- trying to make it easy for newcomers with and without programming experience to write it in a way that feels comfortable, and have things compile correctly the first time (because either way we know what you mean).

djcsdy commented 13 years ago

I half agree with you. Summary:

a: - b

Pros: Obviously an assignment. Cons: Looks almost exactly like it’s assigning a negated value. If you don’t know about half operators, this looks like an unambiguous assignment of a negated value. This is really harmful because it could take a long time to figure out what’s really going on. Even if you do know about half operators, this is likely to cause frequent mistakes and confusion.

a-: b

Pros: Obviously not just a plain assignment. Difficult to confuse with anything else. If you don’t know what this does, you’re likely to look it up rather than try to guess. Cons: Doesn’t look like an assignment.

To me, neither is ideal, but the former approach has massive disadvantages that make it untenable.

djcsdy commented 13 years ago

Oops, didn’t know about the previous discussion, sorry.

To be honest, I’d rather get rid of half operators altogether than have them in their current form. a: - b looks to me like a bigger stumbling block than =/== confusion, and that’s a bugbear of mine too as you can see from my comments above.

karl commented 13 years ago

The docs only show a single example of a half operator:

options: or defaultOptions

Which maps to the idiomatic:

options = options || defaultOptions;

But it is not clear from this that it extends further to other operations, and which operations those might be.

Because of this I always parse half operators (especially plus and minus) as syntax errors in my head. Even knowing how they work now they seem very strange to me, so they may be an area that has a steep learning curve.

Based on my experience I'd lean towards removing or altering them. Unfortunately I don't have an alternate syntax to propose.

TrevorBurnham commented 13 years ago

How about

options or= defaultOptions

I really like the succinctness of half-assignment operators. I also really like =. If == is abolished in favor of is (Issue 519, then it seems to me that there's little reason not to use =. Indeed, not using it would be a waste of a perfectly good symbol and keyboard key. :)

bnolan commented 13 years ago

I'm totally in favour of the colon assignment.

I like it because it feels more functional to me - and somehow syntactically promotes a non-procedural style of programming. I never use the : + syntax - I mix together colon assignment and +=.

zmthy commented 13 years ago

Are half assignments within the scope of this discussion? Colon assignments were around for a long time before the half assignments appeared. Should we, for the sake of brevity and focus, keep this issue within only = vs :?

If = wins out the half operators will probably disappear, but either way we can make it a separate discussion after we decide on the appropriate syntax for assignment (or choose to continue using either).

The decision for either probably shouldn't be weighed by whether or not people like the half operators, as there are definitive alternatives for the operators with the : syntax.

jashkenas commented 13 years ago

Let's set aside half-operators for the moment -- we can re-open the old ticket for them if someone has a complete proposal for replacing them that they'd like to get feedback or votes on.

So tallying up the votes on this ticket, I have 3 people in favor of replacing colons with equals signs (trevor, devon, gfxmonk), and 5 people in favor of leaving the colons as they are (stan, djcsdy, tesco, jashkenas, bnolan). So the colons have it. It doesn't sound like there's consensus about the necessity to kill off equals signs, so I think they should stay: the current status quo of them being available to ease the transition from other languages and allowing folks to write code immediately that feels comfortable is, I think, valuable.

On the other hand, I think it would be great to extend CoffeeScript's current --lint behavior with a little CoffeeScript linting as well. If someone feels like working on a patch that prints linted warnings about equals sign usage, or other un-idiomatic constructs, it would be warmly welcomed.

Closing this ticket as a wontfix.

jashkenas commented 13 years ago

I've taken the time to implement a branch that does away with : for assignment and removes all half assignment as well. Take a look at this ticket, and lend your opinions...

http://github.com/jashkenas/coffee-script/issues/issue/541