-
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
Allow dashes in identifiers, mangle them. #2370
Conversation
my-obj =
key-a: "foo"
key-b: "bar"
get-prop-name = (external-condition) ->
if external-condition then "keyA" else "keyB" # wut
alert(my-obj[get-prop-name()])
#--
my-other-obj =
key-a: "foo"
keyA: "bar" # SyntaxError: you said "keyA" twice. really, you did.
#--
my-third-obj =
key-a: "foo"
my-third-obj.keyA = "baz"
alert(my-obj.key-a) # wut
#--
my-fourth-obj =
key-a: "foo"
`var myObjFromExternalJavaScriptLibrary = {
keyA: "bar"
};`
_.extend(my-fourth-obj, myObjFromExternalJavaScriptLibrary)
# or should I say, my-obj-from-external-java-script-library?
alert(my-fourth-obj.key-a) # damn
#--
four = 4
five = 5
one = five-four # ReferenceError: fiveFour is not defined
one = five-4 # ReferenceError: five4 is not defined
one = 5-four # works, ayup |
@domenic welp. a little problem as compared to readability improvement and implying coffeescript already have inconsistencies of this sort. |
+1 for this as it aids readability and that adds to programmer happiness. There can be confusion as it's been previously mentioned in other threads:
I'm in the camp that the readability benefit completely outweighs the confusion. It's a simple rule to remember. |
Shouldn't even compile. |
@goatslacker Good call, that's a pretty big wtf by itself. |
I personally do not see how it improves readability. I don't have any problems with camelCase as well. |
Btw, i see how it adds a lot of confusion. |
I see profit in making spaces compulsory, if you use - as minus be sure to leave spaces, if no - it is a variable. readability-is-higher - than-it-was |
I always love languages which require spaces around minus since this frees minus to be used in identifiers. So I guess I'm +1 on this. |
LiveScript has this, but allows no spaces around the minus when one of the operands is a number. This fits with the only common use case of a no-spaced minus I can imagine, doing something like |
I like the LiveScript implementation. +1 for adopting that. |
One qualm I would have about the LiveScript behavior is that I tend to be wary of rules that cause surprises when making small mutations to code. For example, say you have a function for getting a previous item in an array, like this: prev = (list, x) -> list[x-1] Later, you decide to make the function more general by adding a prev = (list, x, step=1) -> list[x-step] Under the LiveScript rules, the original version is valid and has expected behavior, but the modified version gets translated to |
I'm afraid the LiveScript version is our only option as decremental operators, which are widely used, would break with this implementation. I think it's bad enough that The RegExp should only allow dashes followed by a letter or number. As far as |
@goatslacker I agree, we should disallow |
Perl6 allows hyphens in names, but only when followed by an alphabetic character:
|
I'm generally -1 on this proposal because Javascript already has 4 uses of minus '-' : binary ( [3,1,4,1,5,9].sort (a,b) -> a-b Principle of least astonishment - The principle of least astonishment is usually referenced in regards to the user interface, but the same principle applies to written code. Code should surprise the reader as little as possible. The means following standard conventions, code should do what the comments and name suggest, and potentially surprising side effects should be avoided as much as possible. |
@josher19 just add spaces around your operators. It is a good practice, actually. |
@goatslacker why not simply say "identifiers may not begin or end with a hyphen, and may not contain consecutive hyphens"? You're going to need those rule anyway (otherwise |
@paulmillr That's easy to do for projects going forward, but a bit more difficult for existing code. Recently I upgraded someone else's code to v1.3.3 and had to spend some time finding all of the places where new keywords (such as a variable named "package") were causing compile time errors. The example I gave above would produce a harder to debug run-time error rather than a compile time error or warning, but other scenarios could fail even less gracefully. Would there be a way to disable the "dasherize" option from the command line or generate warnings where a match is found? Adding spaces around all minus signs ('-') for existing projects might be almost as easy as something like: file.toString().replace /([a-z])-([a-z])/ig, "$1 - $2" Although text in quotes or triple quotes (""") may cause a slight problem: "coffee-script" becomes "coffee - script" @gkz: Current LiveScript implementation compiles |
The tokens produced by CoffeeScript and LiveScript's lexer are identical for both It's also trivial to write a tool that analyzes coffee-script source code for possible clashes with this new feature. I volunteer to make a node module for it if this makes it in. I hope that's not a show stopper :) |
@josher19 I recently pushed a fix for the first issue. EDIT: |
IMHO we dont need one more way to write identifiers. Using hyphens on identifiers gives no real benefit to coffeescript it just adds more redundancy. |
Any 'dynamic' usage would need to use both versions, which has a considerable impact on comprehensibility (see @domenic's first comment for more examples): obj = some-prop: 'whatever'
console.log obj['some-prop'] # Doesn't work, but why? some-prop is given explicitly...
console.log obj['someProp'] # ... does work? But I... I mean... I didn't add it? Also in traces, your A more consistent change would be to allow hyphens in object properties, where no mangling is required: class A
set-name: (@the-name) ->
get-name: -> @the-name
a = new A
a.set-name 'Bob'
alert a.get-name() Compiles to: var A, a;
A = (function() {
function A() {}
A.prototype['set-name'] = function(name) {
this['the-name'] = name;
};
A.prototype['get-name'] = function() {
return this['the-name'];
};
return A;
})();
a = new A;
a['set-name']('Bob');
console.log(a['get-name']()); This would allow people who want to incorporate hyphenated syntax to do so to a reasonable degree (only plain old variables cannot be hyphenated), and creates no major surprises (although it still raises the same syntax issues - This has parallels to how keywords are treated at the moment:
|
@connec i've told about this issue already. Just one simple rule: identifiers are mangled. String is obviously not an, innit? |
Unless I'm misunderstanding something, in your example you say Therefore if you declare an object with hyphenated properties In addition, consider the case were you actually do define a hyphenated property This is a fairly simple rule, but it adds a great deal of inconsistency and potential for confusion, and the benefits of mangling over simply allowing hyphenated properties would, I feel, be lost in the inconsistencies created with respect to string access to properties, names in stack traces, etc. |
But coding CoffeeScript really already requires you to think about the JS translation, and I'm not sure that fact is going to change in the foreseeable future. One of the reasons I love CoffeeScript but could never get behind languages that compile more opaquely to JS is that CS doesn't feel like a different language; it feels like a really warm and fuzzy method for generating JavaScript code, just like C is a warm and fuzzy way of generating assembly. As long as the conversion rules are simple, I don't think that having to think about the JS translation is really a problem. |
I can't tell if this is a really elaborate joke or not. |
@paulmillr underscore is accepted in javascript, and unlike dashes breaks nothing. But CamelCase is the standard thats why most developers use it. Functions without parentheses dont break any javascript feature, and IMHO it is very nice to use on functions that have no arguments. The only point of merging this PR is if are going to start using it as coffee-script standard, otherwise any one who uses it are just fucking with javascript conventions. This may be nice to you but many developers will never use dashes unless it is the standard and I see no point in this-dummy-standard... Imaging teaching coffee-script to a new developer And than you go on ant teach him to debug so you have to tell him that So this PR breaks many features and the only benefit is that it looks pretty to some people. |
For those who are interested how CoffeeScript source looks when written with dashes, here it is https://github.com/paulmillr/coffee-script/tree/topics/use-dashes I've used this script https://gist.github.com/2901194 to convert stuff and then just fixed comments & strings. I especially like how rewriter.coffee looks like now: |
@3den dashes with identifiers don't break any javascript feature because dash identifiers are disallowed in javascript. I think we should disallow calling operators without spacing. Stuff |
@jashkenas what's your opinion on the stuff and prohibiting of |
This is enough to say 'no' to it for me: obj = { cool-stuff: 1 }
# ... later ....
a = obj['cool-stuff'] # undefined??? |
obj = {0xff: 1}
obj['0xff'] # => undefined??? |
obj = {cool-stuff: 1, 'cool-stuff': 2}
obj.cool-stuff # 1
obj.coolStuff # 1
obj['cool-stuff'] # 2 |
obj = { cool-stuff: 1, coolStuff: 2 }
obj.cool-stuff # what should this be?
obj.coolStuff # what should this be? |
@ajoslin not defending them but your example would be: obj = { coolStuff: 1, coolStuff: 2} in javascript if I'm understanding this idea correctly. |
I guess it should have same reaction, as |
Ok, true, compile error. Still confusing though. They definitely look different... |
Sorry to have let this drag on so long before putting this ticket out of its misery ;) CoffeeScript isn't going to mangle identifiers for the same reasons that have been mentioned for underscores and dashes in previous tickets. Most importantly, it breaks rough compatibility with JavaScript. At the moment, JavaScript APIs can be used from CoffeeScript and vice-versa, transparently ... with all of the documentation lining up and being accurate. If we mangled identifiers, you'd always have to be translating into (or out of) camelCase in your head as you read the documentation. Of secondary importance, out of all of the things we might mangle, identifiers are one of the most problematic. Straightforward things like string indexing into objects -- as demonstrated above -- become more painful than they need to be.
|
If you want dashes use something more consistent like: |
yay!!!!! |
Thank god. |
Sanity prevails! |
Phew! |
If this were a couple of months ago, I'd be waiting for the "April Fools".... |
So this wasn't a joke? |
Guys, what is with all the gloating? I was lukewarm on this idea myself, for reasons of personal taste, but coming into a discussion you didn't bother to participate in and gloating and guffawing after the matter has been closed, especially when the subject in question is something someone actually took the time to write up into a pull request including tests... that's just tacky. |
Well, for my part, I would have commented if I'd come across it before it was already closed. Sorry you find the comment tacky. I find your fatherly scolding and air of moral superiority tacky, so I guess we're even. |
Come on guys, its settled. I might not have agreed with it either but hell yeah for the effort Paul! |
You're right. Excellent work Paul. Take care, Brendten Eickstaedt On Jun 15, 2012, at 7:08 PM, David Brear
|
I dint like this PR neither but @paulmillr did a good job to add this feature and I respect that. |
It just needs a small tweak: please consider a Reopen: This patch enables using (...) |
@xk remember to allow identifiers with |
Wtf is this shit?
This patch enables using dashes in identifier names and mangles letters after them to uppercase.
E.g.
for-each
would be compiled toforEach
.This greatly improves readability sticking to idiomatic js output, because you're able to write code in idiomatic js style and everyone would be able to use it without bullshit.
See underscores are stupid. tl;dr: you need to use
shift
to write underscores and camelcase etc.Simplicity
The main point of this pull request is that when you do shit simply, everything is ok.
One simple rule is used: identifiers always mangled. Others aren't.
{parse-int}
would be compiled to{parseInt: parseInt}
.{'parse-int'}
would be compiled to{'parse-int': 'parse-int'}
because string ain't an identifier.object['to-string']
, it's compiled toobject['to-string']
What about interoperability with javascript?
is weak argument because you already need to do mental translation for:
yes
,on
compiles totrue
,no
,off
to falsereturn
is automatically applied to every last statement in function and everything is a statementvar
so you can accidentally reassign some function and spend a hour looking for the bug...
/..
don't give any clarity which one is inclusive.isnt
and there isis not
, but they are not the samefor-in
isn't the same as in js,for-of
isn't the same as in ecmascript 6a- b
vsa -b
Backwards compat
Existing codebases are easy to transfer. Just replace
(\w)([+-*/])(\w)
with$1 $2 $3
in all files.Example 1:
CoffeeScript source rewritten with dashes: https://github.com/paulmillr/coffee-script/tree/topics/use-dashes.
Script used for auto-replacing: https://gist.github.com/2901194.
Example 2:
compiles to
Closes #2345. Thanks @goatslacker for initial work.