Skip to content
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

Is the syntax : and ?= for assignment inconsistent? #261

Closed
drnic opened this issue Mar 16, 2010 · 61 comments
Closed

Is the syntax : and ?= for assignment inconsistent? #261

drnic opened this issue Mar 16, 2010 · 61 comments

Comments

@drnic
Copy link
Contributor

drnic commented Mar 16, 2010

Normal assignment:

food: "carrot"

||= assignment:

food ?= "apple"

These seem inconsistent, perhaps? Not sure what to do about it, just wondered if anyone else thought it.

@weepy
Copy link

weepy commented Mar 16, 2010

It's been discussed a couple of times before. The main reason for not supporting ||: and friends was that they already exist in vanilla JS. Personally I'd favour consistency.

@ghost
Copy link

ghost commented Mar 16, 2010

I agree, it should be "||:", IMO.

@jashkenas
Copy link
Owner

Here's one of the prior tickets discussing this, for context:

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

@devyn
Copy link

devyn commented Mar 18, 2010

It'd be great. : makes a ton more sense for any kind of assignment than =.

@hen-x
Copy link

hen-x commented Mar 18, 2010

Surely internal consistency within the language is more important than parity with other languages, even Javascript. Operators like += stick out like a sore thumb at the moment, because they don't look like an assignment. I think colon-based assignment syntax is one of the really intuitive and aesthetically pleasing elements of CS, but it would make more sense if it looked the same everywhere.

@jashkenas
Copy link
Owner

sethaurus & co: take a look at my proposal towards the bottom of the previously-linked ticket. If we wanted to make it truly consistent, and expression-ish, we would simply remove all modified assignment operators (||=, +=, *=, ?=), and allow you to assign directly to a half-operation.

value: or default_value

x_pos: + x_velocity

account: * daily_interest_rate

I still think that if you're going for consistency and minimalism, that's about the end of the line.

@weepy
Copy link

weepy commented Mar 18, 2010

It's quite neat. The only ambiguity is around -. Presumably you'd need white space after the - to indicate it's a relative assignment ?

@jashkenas
Copy link
Owner

Yep, it would need to be whitespace sensitive. We already have this notion with the spaced property in the Lexer.

@ghost
Copy link

ghost commented Mar 18, 2010

jashkenas:
love your proposal!

that's beauty in a programming language. :)

@hen-x
Copy link

hen-x commented Mar 18, 2010

I'm also keen on that proposal, provided that the unary plus would also be made whitespace-sensitive, so that statements like this would continue to work as expected:

current_timestamp: +new Date() 

@weepy
Copy link

weepy commented Mar 18, 2010

how would u deal with /

c: / 2 / 

@hen-x
Copy link

hen-x commented Mar 18, 2010

Regexes in CoffeeScript are not allowed to start with a whitespace character, so that line would remain a syntax error.

@timbertson
Copy link
Contributor

ack, making
x: -2
different to
x: - 2

sounds like a recipe for confusion. Whitespace-sensitive indenting makes sense, introducing whitespace-sensitive expressions is likely to make people confused and superstitious...

To be honest I'm not a fan of the colon in the first place (cos you need to press shift ;)), but I would much rather see the modifying-assignment operators replicated in coffeescript, but with the equals replaced with colons (eg += becomes +: and *= becomes *: ).

I'd also quite like the existing operators to still work, because personally they make more sense to me. But for purity's sake I'm okay with them disappearing.

@ghost
Copy link

ghost commented Mar 19, 2010

gfxmonk: Its not clear because your sample code is not in a fixed-width font.

In a fixed-width font, that sort of code looks much clearer. Try Monaco 13 if you're on a Mac.

@timbertson
Copy link
Contributor

Yes, the font makes a difference. But I'm not sure why you would want to have to go to this effort when the existing operators (or their colon-replaced bretheren) are perfectly unambiguous and reasonably well understood.

@jashkenas
Copy link
Owner

gfxmonk: That's precisely the issue (and the reason we didn't do it last time). You get to remove a bunch of operators, but you have to deal with the potentially annoying, and certainly unexpected whitespace, not to mention that strange aftertaste...

I'm sure that you could get used to it in time, and if you were looking at the language tabula rasa, you might very well even pick it up faster, but it's one of those things that's six of one, half-dozen of the other.

Hence the yeas and nays.

@weepy
Copy link

weepy commented Mar 19, 2010

The other thing that could be done is to invert the operators, so that the assignment colon is still on the left:

value:|| 1
x_pos:+ 2
account:* 123
y :- 2

That way we don't need to worry about the whitespace issue, but we get the benefit of the consistency.

@ghost
Copy link

ghost commented Mar 19, 2010

weepy, yes, this may be the best way to conciliate the 2 differing views on the matter.

...Although I must say I still prefer Jashkenas' previous proposal. :)

The worse, IMO, is the current inconsistency in the syntax.

@drnic
Copy link
Contributor Author

drnic commented Mar 19, 2010

I like weepy's suggestion

@zmthy
Copy link
Collaborator

zmthy commented Mar 19, 2010

Does that really solve the problem? Isn't
value:-2
still ambiguous?

@ghost
Copy link

ghost commented Mar 19, 2010

Tesco,

value:-2

...wouldn't be valid.

But this would:
y:- 2
...for decrementing.

And this:
y: -2
...for assigning to negative values.

@timbertson
Copy link
Contributor

that's still an awful lot of surprise for a misplaced space (and ambiguity for an omitted one), where the current syntax (or the original CS operators with the colon-replacements) has no such surprises or ambiguity.

@tim-smart
Copy link
Contributor

that's still an awful lot of surprise for a misplaced space

I agree, and this is how I would expect it to work.

These are allowed:

name: value
name = value
name += value
{ name: value }

These aren't allowed:

name +: value
// etc
{ name = value }
// So people don't also expect this to work
{ name += value }

I would also think about dis-allowing the extra assignments all together, forcing people to write:

name: name + value
name: name * value
name: value if true

etc. Almost always means more readable code. Could also mean:

=
// Compiles to
===

But probably not a good idea :p But it does bring a whole new element back to simplicity:

x: 2
y: x + 2
if x - 2 = y then do_something()

@zmthy
Copy link
Collaborator

zmthy commented Mar 20, 2010

I personally think we should drop = altogether, remove all this inconsistency. I suppose there must be overwhelming support for using it, though?

@drnic
Copy link
Contributor Author

drnic commented Mar 20, 2010

To reduce confusion the supported tokens can be syntax highlighted in editors. Common errors can be also highlighted as an error. For example in the Ruby textmate bundle, ~= highlights as a nasty error.

Also, ppl mistype things all the time. Unit tests pick these things up.

@ghost
Copy link

ghost commented Mar 20, 2010

drnic, yes, I was mentioning syntax highlighting to gfxmonk the other day, I also think that would be a great way of making those distinctions more clear, and allowing the developer to get immediate visual feedback on what's valid and not.

@ghost
Copy link

ghost commented Mar 20, 2010

Tesco, yes, "drop '=' altogether", that's what weepy's proposal was all about.

@wlangstroth
Copy link

weepy's :+ seems pretty intuitive and consistent to me (for what that's worth). I would have to look at the code more closely, but is there harm in making

y:- 2
y :- 2
y: - 2

all perform y -= 2, where y: -2 would be the expected assignment of -2? In terms of language design, I mean, not the hassle to implement it. (That's obviously an important consideration, but I'm asking whether the -= is what people are used to, rather than what makes sense.)

@StanAngeloff
Copy link
Contributor

I'd like to see some consistency with the operators, but I'd hate to have to worry about whitespace getting in the way. I reckon weepy's proposal is by far the most intuitive one and it shouldn't lead to any errors if whitespace is applied mistakenly.

On the other hand, since CoffeeScript compiles to JavaScript it would be nice to have some backwards compatible operators, such as the +=, -=, etc. It will make it difficult for newcomers to adopt :+ and the rest as it makes the learning curve steeper.

So my suggestion is keep the existing JavaScript operators, but allow for Coffee's own ones as well.

@weepy
Copy link

weepy commented Mar 21, 2010

langstroth: I don't think y: - 2 should be a decrement, i think the : and - should be next to each other to perform.

@devyn
Copy link

devyn commented Mar 21, 2010

langstroth: I couldn't agree more. CS itself may be just for fun, but it is actually quite practical for a JavaScript semi-alternative (not quite sure what to call it...) Therefore, I think we should do whatever we can to make it awesome.

@devyn
Copy link

devyn commented Mar 21, 2010

Get rid of = for assignment altogether, and instead use it for testing equality. If I showed == to my math teacher, or pretty much anyone who doesn't code, they would most likely be confused.

@matehat
Copy link
Contributor

matehat commented Mar 22, 2010

I also agree with all folks praising consistency over compatibility. As to the steepness of the learning curve, I think it would be less confusing if we stay consistent all the way, than if we have different ways of writing the same thing += <-> :+.

@matehat
Copy link
Contributor

matehat commented Mar 22, 2010

Also in favor of = replacing == and ===, but only if we remove all the = variants.

@wlangstroth
Copy link

matehat: that's what seems to be the most sensible thing. Of course, there's also is ...

@zmthy
Copy link
Collaborator

zmthy commented Mar 22, 2010

But that's keywords versus symbols, rather than multiple symbols.

@tim-smart
Copy link
Contributor

@jashkenas
Copy link
Owner

This is still very much an open issue, but we now have a first draft of a proposed solution on master, so give it a spin and see what you think. It's largely backwards-compatible with the current syntax, but enables assigning to a half-expression, which is the form that the entire compiler now uses. So you'll see bits like:

levels[open]: + 1

And...

value: or @chunk.substr(0, 1)

This gets rid of the inconsistency between assignment and operator-assignment, that drnic raised in the original posting. You can now avoid = entirely, if you so choose.

: is still interchangeable with =, and both of the examples above can be rewritten to use it, if desired.

The disambiguation of : - is also whitespace sensitive as discussed above.
val: - 1 is val -= 1, and val: -1 is val = -1.

For a more minimal alternative, take a look at Tim Smart's branch.

@devyn
Copy link

devyn commented Mar 22, 2010

I think we should keep is, not, and the other keywords, because although = and is compile to the same thing, they're semantically different. IMO, =, != are for (mainly) mathematical comparisons, is, is not are for strings and objects (mainly). And I'd prefer if not @ready? over if !@ready? We'd lose little semantic things like launch() if ignition is on and volume: 10 if band isnt spinal_tap. I think we should allow both.

Just my 2¢ from looking at Tim Smart's fork.

@tim-smart
Copy link
Contributor

OK. I have done a bit of hacking, and come up with http://github.com/Tim-Smart/coffee-script/compare/simplicity

  • is and = are interchangeable, both compiling to ===. I think the combined use of them is nice.
  • += and friends are gone, in favor of name: + 1 etc.

In summary, all = assignment is gone.

@devyn
Copy link

devyn commented Mar 23, 2010

Looks good! But I'm not sure which one is better, name: + 1 or name :+ 1. name: + 1 looks nice, so, I don't know. Anyhow, good job.

@timbertson
Copy link
Contributor

I think some thought should be given to the poor javascript programmers who are moving to CS - that is, after all, the main audience.

Perhaps it could be an error (or warning) to have an "=" operation that is not used or assigned anywhere?

i.e if I write "foo = bar", and that's not part of a bigger expression or assignment, then chances are I meant "foo: bar"

Also, the whitespace rules for the new increment operators are confusing me. For example, why doesn't "i:-1" compile, nor "i:- 1". I'm not sure if we want the first to do something as it's ambiguous, but the second is clearly a decrement.

@tim-smart
Copy link
Contributor

Yeah i:-1 has always thrown an error. I think its a bug that needs ironing out. It would be nice to make these cases valid:

// Increments
i :+ 1
i:+ 1
i: + 1

// Assignment
i:+1
i: +1

I'm not sure what the road block is at the moment, but hopefully it can be cleared soon.

In terms of foo: bar, and foo = bar, I would prefer one or the other, otherwise everything just gets a little wishy-washy.

@devyn
Copy link

devyn commented Mar 23, 2010

Tim-Smart: Well said. +1

@mgiuca
Copy link

mgiuca commented Mar 23, 2010

Sorry to butt in here (I'm not a CS user, so my opinion is fairly void), but I just thought I'd point something out with respect to the proposed :+ and friends operators. (Disclaimer: I'm a friend of gfxmonk, but my opinions are my own.)

You are recreating a mistake from the early 70s which was fixed, and remained fixed in all subsequent programming languages. The B programming language, predecessor to C, is described here:
http://cm.bell-labs.com/cm/cs/who/dmr/kbman.html

It featured update-assignment operators =+, =-, =|, =&, etc, which perform a binary operation between the l-value and r-value and update the lvalue. It was quickly discovered that this was a great idea, but with a terrible syntax, because of the ambiguity of "i=-10" (does it mean "i = i - 10" or "i = (-10)"?)

This was carried over into the very early versions of C, until K&R C in 1978, which changed the operators to the now-familiar +=, -=, |=, &=, etc, which aren't ambiguous since none of those operators can appear at the end of an expression.

The Wikipedia article for C explains this: "compound assignment operators of the form =op (such as =-) were changed to the form op= to remove the semantic ambiguity created by such constructs as i=-10, which had been interpreted as i =- 10 instead of the possibly intended i = -10".

Your new syntax is almost exactly the same as B's compound assignment operators (with the only difference being allowed whitespace between the ':' and the operator). It would be the same mistake.

I would agree with gfxmonk's (and K&R's) suggestion that you swap them around, having the "+:", "-:", etc operators. That would be familiar to anyone using the C family, only with '=' replaced with ':'.

@devyn
Copy link

devyn commented Mar 23, 2010

mgiuca: hmm, something to think about, for sure. I don't know, because many people also have said that significant-indentation is a horrible idea, and yet, look how well it turns out in most cases (CS itself is a prime example)

@tim-smart
Copy link
Contributor

because of the ambiguity of "i=-10"

created by such constructs as i=-10, which had been interpreted as i =- 10 instead of the possibly intended i = -10".

i:-10 would be interpreted to i = -10, due to the whitespace sensitivity in Coffeescript. C isn't whitespace sensitive in the same sense, so the ambiguity issues are more of a problem.

Still it is a (partial) issue, and I'm not sure why +: and friends were rejected.

@mgiuca
Copy link

mgiuca commented Mar 23, 2010

I think significant-indentation is a great idea (I am a Python fan; as I said I haven't used CS). However, that's different to this, because you only need to worry about the start of the line, which everyone agrees should be indented (the disagreement is over whether you should be forced to indent).

However, there is no general consensus on when to use whitespace in between expressions and operators. I usually use whitespace unless I'm running out of space on a line or am deeply-nested. You don't want that sort of thing determining your semantics.

At least it is a good thing if i:-10 is an error, rather than choosing one over the other (so there is no "accidentally got the wrong semantics"). Therefore you need to explicitly use i: -10 or i:- 10, to prove to the compiler that you know what you mean. Tim-Smart said it should be assignment, I think it should error.

And i: - 10 is similarly ambiguous since you might mean to use the unary minus operator with a space between it and the expression (why not? Binary operators are commonly written with spaces, why not unary?) So the rule must be you are allowed to have whitespace on exactly one side of the operator symbol.

@tim-smart
Copy link
Contributor

Therefore you need to explicitly use i: -10 or i:- 10

I like and agree with that.

@StanAngeloff
Copy link
Contributor

Indentation-sensitive blocks are fine, but whitespace-sensitive operators? Really? There is just room for so much error with the latter approach. If there is one thing I hate in any programming language, it is enforced conventions. If I like to write my assignments as i: - 10 there shouldn't be anything stopping me from doing so.

Since we are compiling to JavaScript, most people using Coffee will have JavaScript background. JavaScript is not whitespace-sensitive, would whitespace-sensitive operators make sense to them?

Looking back at topics we have discussed before -- classes and constructors. In prior versions it was mandatory to return this at the last line of the constructor. It was a convention, it was an enforcement -- it was bad. This has since been reworked to use the new class construct and it is much more friendly and there is less room for errors.

So to recap in the shortest possible way, +: and -:, etc. should be just fine.

@weepy
Copy link

weepy commented Mar 23, 2010

I think whatever is simplest should win out here. If it was up to me I'd just stick with +: and friends as they work unambiguously and follow the path of least confusion. i: + 5 clouds the idea of the operator here and brings in unnecessary confusion around whitespace issues, for little tangible gain.

At the end of the day it's not as though these operators are used that often (+: is by far the most used).

@devyn
Copy link

devyn commented Mar 23, 2010

yeah, these are used far less in CS than they are in JS

@tim-smart
Copy link
Contributor

After using foo: + bar for a little bit (now that it is on master), it seems rather nice. It also means you can use word operators foo: and bar without looking really weird (foo and: bar). Just another 2c coin to chuck in with the others.

@timbertson
Copy link
Contributor

I find exactly the opposite. Where previously I would pause briefly to remember which of ":+" or "+=" I should use, I now find myself pausing for far too long remembering where I should put my whitespace.

@jashkenas
Copy link
Owner

This is great -- it's funny how the smallest things can raise the most controversy.

If you find this confusing, or don't want to deal with whitespace, that's fine: You can continue to use the familiar -=, +=, ||= operators from JavaScript, Ruby, and many other languages. In 0.5.6, they continue to work as expected. If you find yourself worrying about whitespace, feel free to reach form them -- they're not going anywhere.

But if you'd like to clear out your operator palette, the compound assignment that the new options: or {} syntax offers is a nice way to clean things up. I'm certainly enjoying it.

The only ambiguity that should be a problem is the unary minus, as mentioned above. And I don't think it's too much to ask for unary minuses to be attached to their value. We're already whitespace sensitive to a further degree than Python is.

@wlangstroth
Copy link

As Tim-Smart said, the type of operator proposed would only be a mistake if whitespace were to be ignored. Whitespace being a significant part of a language isnothingterriblynew.

@timbertson
Copy link
Contributor

langstroth: indentation-sensitive statements are a different beast to whitespace-sensitive expressions. I don't know of any other modern language that has whitespace-sensitive expressions (discounting the perverse "whitespace" language itself, of course ;)).

jashkenas: thanks for clarifying, I got lost amongst the proposals and thought that += and friends had already got the chop.

w.r.t being more whitespace-aware than python, I assumed CS only used whitespace for blocks (while bodies, function bodies, if bodies, etc). That seems roughly on-par with python, except for allowing statements inside an anonymous function (lambda). Are there any other differences? I haven't had the guts to peer into the parser to check for myself ;)

@wlangstroth
Copy link

gfxmonk: of course you're right, but that's not a reason to keep from trying it out. There may, in fact, be compelling reasons not to have whitespace-sensitive expressions, but "nobody else does it" isn't one of them. Neither is "it's not enough like JavaScript". Why would it need to be? It's a fun code-translation project! I'm not saying I'd be as interested if it were a brainfuck-to-JavaScript compiler, I'm just saying this would be the place to try out different things.

@timbertson
Copy link
Contributor

That's true, although I see CS as a great alternative to javascript, and would be sad if it didn't get much uptake because because it tried out too many whacky ideas. Well, to be precise: trying out whacky ideas is fine - not reversing them when they turn out to be too whacky would be bad. So I should hold my tongue and wait to see what people actually think of using the new operators. I wonder what is a reasonable amount of time for assessing the success of this sort of thing? And where does the feedback come from?

I know I'm being overly dramatic for a fairly unimportant set of operators, but I believe getting stuck with too many interesting ideas is what made javascript an unfortunately awkward language in the first place.

Also mgiuca did point out the pretty convincing (although I am biased) historical reasons for the operators most languages have today - it's not simply that "nobody else does it"

@ghost
Copy link

ghost commented Mar 24, 2010

"(...) the compound assignment that the new options: or {} syntax offers is a nice way to clean things up. I'm certainly enjoying it."

+1

I'm a fan of the new syntax as well.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests