-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Multiple existential operators work weirdly. #2199
Comments
Our binary existential operator associates to the left. |
👍 for right associativity. OP isn't the only person who expected it to behave like |
|
@glitchmr I wouldn't be surprised if the existential operator were actually inspired by Perl's Perl's semantics also differ from CoffeeScript's. With
|
Yeah, you're right. But, because of short-circuit evaluation property of (yeah, you can tell I don't understand concepts on associativity :P) |
Well, it's tempting to read that statement as If That is assuming that all the variables you need to test exist: Javascript won't accept an undefined reference in there. Which is where Unfortunately while the So: I don't think making That way any number of chains will work, and we'll still do the least amount of work to get to it. |
If making ? left associative is a "breaking change", then
which becomes
which compiles to this Javascript (unless variables are already defined and it uses != null instead):
and works kind of like you'd expect Why another operator? Right now a = b ? 'c' but in fact, they are not:
and these two are the same:
|
Except that: a? b
a ? b This is not really a problem. Many more operators are context sensitive like this. To give examples, Those four examples below are different. But it's sort of intuitive. func (a) + b
func(a) + b
func (a) +b
func(a) +b |
I'm confused here, because as far as I can tell -- the logical operators |
Binary
|
Sorry to be repetitive, but why do we want it to be right-associative? In logic, and in JavaScript, logical operators are left-associative. https://developer.mozilla.org/en/JavaScript/Reference/Operators/Operator_Precedence |
$ coffee -bpe '(a, b) -> console.log (a ? b ? c)' (function(a, b) { var _ref; return console.log((_ref = a != null ? a : b) != null ? _ref : c); }); $ coffee -bpe '(a, b) -> console.log (a ? (b ? c))' (function(a, b) { return console.log(a != null ? a : b != null ? b : c); }); $ edit: Comment removed. See @josher19's comment below for the more important example. |
Problem is that:
becomes
compiles to buggy: variable = (_ref = typeof a !== "undefined" && a !== null ? a : b) != null ? _ref : 'default'; which throws a ReferenceError for undefined b, when you'd expect it to be equivalent to coffeescript:
which correctly compiles to: variable = typeof a !== "undefined" && a !== null ? a : typeof b !== "undefined" && b !== null ? b : 'default'; and gets the correct answer of 'default'. ->> Josh W <<- |
In Javascript, the conditional operator (?:) is right-to-left, and since the binary existential operator compiles to a conditional operator, it really should be right-to-left. Or if that will break code, you could create a '??' operator which is right-to-left. |
I'm afraid I don't see how it's more useful or expected if the expected thing is to be left associative. If when I look at
... then when I see
.. if a doesn't exist then b, and if the value of all that still doesn't exist then c. I think changing this would break logical consistency. |
@jashkenas: I think you should take a look at those compilations again. See that they both align with the behaviour you expect in the case that the first two operands are declared. But in the case that the first operand is null or undeclared and the second operand is undeclared, the suggested compilation succeeds while the current compilation fails. I don't think this is a matter of opinion here -- the right-associative compilation is always superior. |
It's not a matter of success or failure, or superior and inferior ... it's a matter of different semantics. Take this example:
If If Leaving it left-associative is consistent with the rest of our logical operators. |
That's only if it's at the same precedence level. If it's higher precedence than |
In terms of CoffeeScript precedences, they're all the same -- |
Oh, wow, you're right. I never noticed that. That's probably very unexpected behaviour for people coming from... pretty much anything else. Have there been issues discussing that? |
No -- because it doesn't make a semantic difference in our case (we're not adding parentheses where none are required). The underlying JavaScript order of operations really rule the day. |
Ah, I see. I just looked at the parse tree and was shocked. But when it's output without grouping, JS precedence takes over. Got it. |
Agreed.
Right. This is why I was able to change LOGIC to right-associative with minimal changes to |
I think that's a smart move for CoffeeScript. @jashkenas: Will you consider that? |
Sure -- if y'all think it's the better thing to do, keeping in mind that in logic proper, these operators are left associative. |
Instead of making all of LOGIC right associative you could make TRI with lower precedence and right-associative, and have I could help make a test suite from existing issues which mention "Existential" or you could just test against a few big Coffeescript projects on npm or github as a "representative sample" and see if things break. If it looks like code might break you should either make it a v1.4 milestone with ample warning or create a new Let me know if there is anything else I can do to help. ->> Josh <<- |
A pull request for this would be considered, but I’m not sure it’s worth doing at this point due to the breaking change it would cause. |
This code returns "ReferenceError: Undefined variable: b" in CoffeeScript (I've tested 1.2.0 and 1.2.1-pre).
This issue doesn't happen in Coco. Also, following code doesn't cause this issue.
The text was updated successfully, but these errors were encountered: