jashkenas / coffeescript

Unfancy JavaScript
https://coffeescript.org/
MIT License
16.52k stars 1.99k forks source link

CS2 Discussion: Question: CoffeeScript Gripes? #4911

Closed coffeescriptbot closed 6 years ago

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13 Originally created by @rattrayalex on Sat, 23 Jul 2016 15:40:35 GMT


What features or aspects of CoffeeScript have caused you the most pain?

What do newcomers to the language find the most challenging?

What are examples of CoffeeScript code that can be particularly confusing?

What features have you almost never seen used that could probably be removed?

Let's use this thread for brainstorming ideas, and try to split off discussions into other threads. Reactions ( ๐Ÿ‘ , ๐Ÿ‘Ž ) encouraged โ€“ ๐Ÿ‘ means "I agree this is a problem" and ๐Ÿ‘Ž means "I disagree โ€“ย this is a good feature and should be kept"

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236139249 Originally created by @carlsmith on Fri, 29 Jul 2016 09:44:31 GMT


If you have access to the iteration counter, it seems intuitive to be able to modify the iteration.

If we're talking about iteration specifically, it pretty directly refers to executing some subroutine for each item in some sequence, so there's an expectation that it's not going to jump around. Still you're right, there's a need to manually advance the iteration counter sometimes. In a lexer for example, you want to iterate over the chars in the source, but if you use a big for char in source loop, you find you need to skip ahead to pop the characters off as you process each token. In those cases, it's best to scrap any pretence of being an iteration, and just use a while-loop that spins forever, then keep track of the character index manually and break manually when you're done. Basically, if it's not a proper iteration, just fall back to a good old fashioned loop and counter. Obviously, it's perfectly fine to use continue in a for-loop, but that doesn't solve the problem you hinted at.

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-234798333 Originally created by @ohaz on Sun, 24 Jul 2016 19:55:12 GMT


Sorry, but that looks kind of bad and poorly readable @ozjd - the loop variable should be changed in the head of the loop only - changing it in the body as well will just make it completely unreadable. Add a "continue", or make the loop skip every second entry by doing it in the loop somehow (like "for name, i in names by 2).

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236365230 Originally created by @objectkit on Sat, 30 Jul 2016 13:27:41 GMT


There are a few gripes I'd like to throw in here myself, but I'll pare it down to just one here...

Implicit Return Must Die

No. Just no. I understand the utility of implicit returns for visual clarity in small methods.

class Data
    constructor: (@value) ->
    getValue: -> @value

and at times, when iterating or filtering arrays and returning the result, but returning undocumented or non-obvious values ad hoc as a result of brevity...? I could be alone in this. But no. Implicit return must die in a new edition of the language. If there is going to be an implicit return, do what ES does and return undefined!

Theres a whole spate of backwards compatibility issues of course, but I think a partial solution could possibly be for this languages compiler to take standard CS in as an input, and to transpile that to CS6 before transpiling to the end language - ES4/5/6/7...

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-234792133 Originally created by @ozjd on Sun, 24 Jul 2016 18:05:21 GMT


The one thing that has always driven me crazy is not being able to modify the incremented variable in a for loop. eg, If I want to skip an iteration.

for name, i in names
  i++

i++ would be expected to skip an iteration, as it assumed that i will automatically be increased in this for loop. Thoughts?

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-234798636 Originally created by @ozjd on Sun, 24 Jul 2016 20:01:01 GMT


If you have access to the iteration counter, it seems intuitive to be able to modify the iteration.

In the end, I created a variable that's checked on each iteration, and skips over the loop as needed.

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236375661 Originally created by @carlsmith on Sat, 30 Jul 2016 16:46:38 GMT


I don't think it's possible to decide return statements on a compiler level. If you are creating a library, how are you to know if the return statement will be used or not if the user script isn't available?

I don't understand. It's only syntactic, and only matters to the author of the function. When you call a function, you never know how it returned a value. It doesn't matter.

Btw, at work we have used CoffeeScript on slow set top boxes for years, boxes with max 2MB JS memory heap until stuff gets garbage collected. You can definitely say that we have had a close eye on memory allocation with proper profilers for years, and CS has never created trouble for us. Even for us, functions as expressions is a positive and has never given us problems.

That's really interesting. Browsers spend very little time executing JS. I assume it's similar with set top boxes. Pure JS stuff, like the CoffeeScript compiler seem fine as well. I've never seen a concrete example of implicit returns being a problem, but a lot of people want a way to disable it (per file or per function with special operators).

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236367581 Originally created by @carlsmith on Sat, 30 Jul 2016 14:16:33 GMT


The argument, which I personally don't care about much, except because other people care about it a lot, is that the return values can be large, and there's a perceived inefficiency in generating and returning big chunks of stuff when it's immediately garbage collected. We could maybe be more intelligent about it at the compiler level, eliminating implicit returns wherever we are certain they go unused. The argument seems to be purely based on perf, so eliminating the inefficiencies would help solve the issue, without changing the language, as I understand it. Again, it's something I only worry about because a lot of other people hate the feature, so I'm not the best person to judge solutions.

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236022891 Originally created by @carlsmith on Thu, 28 Jul 2016 20:57:18 GMT


@rattrayalex - Done. No worries.

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-235180239 Originally created by @JimPanic on Tue, 26 Jul 2016 07:04:13 GMT


In the case of any syntax similar to for x, y in {key: value, ...}, this doesn't make any sense. The syntax is basically an implicit map function invoking the expression you give it. If it does work, I would highly recommend against using this. This is a fast lane to hard-to-debug bugs.

It would be possible and is used heavily in for(i = x; i < y; i += 2) { i -= 1;} constructs, but we do not have those in CS as far as I can tell.

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-235958839 Originally created by @carlsmith on Thu, 28 Jul 2016 17:03:39 GMT


Nonlocal Assignment

As discussed at length in https://github.com/coffeescript6/discuss/issues/1, CoffeeScript uses nonlocal assignments by default, which is unusual and confusing.

Remove the Arguments Type

Make it a normal array (if it's actually referenced).

Array Comprehensions

CoffeeScript operator precedence makes a = b for b in c equal to (a = b) for b in c, so a gets reassigned on every iteration. You normally want to do a = (b for b in c), so a is assigned once, to an array of the values from each iteration. We should require array comprehensions to be wrapped in brackets: a = [ b for b in c ].

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236381388 Originally created by @rattrayalex on Sat, 30 Jul 2016 18:27:49 GMT


@carlsmith

This has been discussed before

Can you provide a link?

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236371205 Originally created by @carlmathisen on Sat, 30 Jul 2016 15:26:58 GMT


I don't think it's possible to decide return statements on a compiler level. If you are creating a library, how are you to know if the return statement will be used or not if the user script isn't available?

Btw, at work we have used CoffeeScript on slow set top boxes for years, boxes with max 2MB JS memory heap until stuff gets garbage collected. You can definitely say that we have had a close eye on memory allocation with proper profilers for years, and CS has never created trouble for us. Even for us, functions as expressions is a positive and has never given us problems.

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-235186610 Originally created by @JimPanic on Tue, 26 Jul 2016 07:39:26 GMT


Additionally, you might want to use a reduce/fold function instead where you use the accumulator as arbitrary counting variable.

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236395151 Originally created by @carlsmith on Sat, 30 Jul 2016 23:13:30 GMT


Can you provide a link?

This has been discussed a bunch of times. Here's some examples; there are more:

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236402015 Originally created by @rattrayalex on Sun, 31 Jul 2016 01:40:10 GMT


Great idea! https://github.com/coffeescript6/discuss/wiki let me know if you have any challenges

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236859109 Originally created by @mrmowgli on Tue, 02 Aug 2016 09:58:01 GMT


I think one of the things I constantly am surprised isn't there is the ternary operator. (bool)?true:false

While I understand the idea behind having the code be more readable, it is still an exceptionally useful construct. Breaking things into multiple line if statements in this case is always a pain.

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236399918 Originally created by @carlsmith on Sun, 31 Jul 2016 00:51:36 GMT


No problem mate. It's worth gathering these lists together. We should maybe put them in the wiki so everyone can edit them, and start collating all the previous discussions from CS, Redux, Coco etc. that are relevant and valuable. It'd be a good resource for all the CoffeeScript family of projects, whenever anyone needs to see what's been said in the past about a feature. Issues is a good place to discuss stuff, but GH wikis are really cool as well for the right content.

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236397638 Originally created by @rattrayalex on Sun, 31 Jul 2016 00:02:32 GMT


Wow, some really terrific discussion there. Thanks for digging those up @carlsmith !

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236381828 Originally created by @rattrayalex on Sat, 30 Jul 2016 18:34:57 GMT


Removing implicit returns would present backwards-incompatibility pains of astonishing proportions (regardless of whether they're a good idea in general or not).

Personally, I ported the entire frontend codebase at work from coffeescript to es6 several months ago, and removing return statements that were added implicitly, but never used, was the biggest pain I had to deal with. So I do agree that they're a problem.

@objectkit what do you think of a way of silencing implicit returns? Something like -%> (ideally we'd find something prettier).

Either way, @objectkit would you like to open a new thread to discuss implicit returns?

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236365706 Originally created by @carlsmith on Sat, 30 Jul 2016 13:38:04 GMT


We must implicitly return something, as a function call is an expression. It could be undefined though. I would rather have it so that functions that have a single expression as their body return its value implicitly, but functions with more than one expression must return something explicitly, else undefined.

This has been discussed before, and a few of us wanted that compromise.

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236367128 Originally created by @MemoryChips on Sat, 30 Jul 2016 14:06:25 GMT


What do you save by getting rid of implicit returns? You would have to type return a heck of a lot more often if you get rid of it.

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-235961705 Originally created by @rattrayalex on Thu, 28 Jul 2016 17:14:07 GMT


@carlsmith wow, awesome list!!

Many things seem more like feature requests than gripes, however. I just created a "New Feature Ideas" thread โ€“ย https://github.com/coffeescript6/discuss/issues/16 โ€“ย any chance you'd be willing to break out the feature requests to that one?

For example, I personally love the "Automatically Reference First Args" idea, but it's definitely not a bug in coffeescript that the feature doesn't exist yet.

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236376712 Originally created by @carlmathisen on Sat, 30 Jul 2016 17:05:18 GMT


That's really interesting. Browsers spend very little time executing JS. I assume it's similar with set top boxes. Pure JS stuff, like the CoffeeScript compiler seem fine as well. I've never seen a concrete example of implicit returns being a problem, but a lot of people want a way to disable it (per file or per function with special operators).

It is passed by reference anyway, not as a copy. And the return statement won't stay in memory unless you decide to save it on purpose when you call the function.

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236376037 Originally created by @carlsmith on Sat, 30 Jul 2016 16:52:38 GMT


I don't think it's possible to decide return statements on a compiler level. If you are creating a library, how are you to know if the return statement will be used or not if the user script isn't available?

I don't understand. It's only syntactic, and only matters to the author of the function. When you call a function, you never know how it returned a value. It doesn't matter.

Sorry. I was thinking of having implicit returns in functions that only contain one expression. When it comes to only imlipicitly returning things if they're used, you're right. I don't know what I was thinking, but yeah, it wouldn't work.

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236400159 Originally created by @carlsmith on Sun, 31 Jul 2016 00:57:02 GMT


If you create a wiki and open it up to the public, I'll make a page for Implicit Return, with a quick summary of the feature, and the start of a list of previous discussion. I'll look on Google to see if Ashkenas or anyone with interesting views has blogged about it or whatever too.

The wiki would be good for documenting ES6 features, just covering the stuff that's particular to CoffeeScript, linking to the ES6 docs, and summarising our project's current consensus on the feature once there is one etc.

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236585428 Originally created by @objectkit on Mon, 01 Aug 2016 13:49:11 GMT


Hello all - I feel it looks as if I just threw a grenade full of my own linguistic biases into a conversation then fecked off over the hill! Not so - my time is pretty broken up and I meant to get back here much sooner that this. Apologies!

Anyway, great to see feedback and the new wiki entry! @rattrayalex - sure, I'll give silent implicit return syntax a look

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236428636 Originally created by @carlsmith on Sun, 31 Jul 2016 12:59:02 GMT


Nice one @rattrayalex. Cheers. I just added the page to the wiki.

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236611622 Originally created by @dadleyy on Mon, 01 Aug 2016 15:17:47 GMT


I think at this point it behooves us to open a stand-alone issue for implicit return and move the discussion there?

Side note - nice work @carlsmith on the wiki page and @rattrayalex for starting all of this cs6 discussion. I'm very excited about whats happening here.

coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236862036 Originally created by @carlmathisen on Tue, 02 Aug 2016 10:11:15 GMT


@mrmowgli: You could always do a one liner like this.

result = if condition then true else false
coffeescriptbot commented 6 years ago

Migrated from https://github.com/coffeescript6/discuss/issues/13#issuecomment-236871844 Originally created by @JimPanic on Tue, 02 Aug 2016 10:59:16 GMT


Or just

result = condition is true
coffeescriptbot commented 6 years ago

From @kirly-af on Aug 5, 2016

Or even

result = condition
coffeescriptbot commented 6 years ago

From @DomVinyard on Aug 8, 2016

Or even

condition

;)

coffeescriptbot commented 6 years ago

From @GeoffreyBooth on Sep 5, 2016

Just wanted to add regarding the implicit return, it bit me once when writing some tasks for Gulp where Gulp would treat a task returning truthy as having run, versus returning void (like a JavaScript function without a return) would be treated like a promise. (Or something to this effect, it was awhile ago, I donโ€™t remember exactly.)

Anyway I solved it by just putting return on its own line at the end:

module.exports = (gulp, plugins, config) ->
  (done) ->
    # Get latest git commit log, save into an environment variable for Browserify/envify to insert into our app
    plugins.git.exec
      args: "log -1 --pretty=format:\"{%n  \\\"commit\\\": \\\"%H\\\",%n  \\\"author\\\": \\\"%an\\\",%n  \\\"authorEmail\\\": \\\"%ae\\\",%n  \\\"date\\\": \\\"%ad\\\",%n  \\\"message\\\": \\\"%s\\\"%n}\" --date=iso8601"
      quiet: yes
    , (err, stdout) ->
      if err then throw err

      # Escape any quotes that might be in the commit message
      find = stdout.match(/\n  "message": "(.*)"\n}/m)[1]
      replace = find.replace /"/g, '\\"'
      stdout = stdout.replace find, replace

      # Save and output
      process.env.COMMIT = stdout
      config.commit = JSON.parse stdout
      plugins.util.log "Building commit #{config.commit.commit}: " + plugins.util.colors.yellow config.commit.message
      done()

    return

This is hardly a terrible workaround. You could also just put no or null on its own on the last line, if youโ€™d rather return a falsy value than โ€œvoidโ€.

coffeescriptbot commented 6 years ago

From @rashfael on Sep 6, 2016

That implicit return workaround became convention in our team:

No Implicit Returns: Always explicitly return in functions with more than one statement

Which kind of defeats the purpose of an implicit return.

Some examples that forced us to create that rule:

coffeescriptbot commented 6 years ago

From @carlsmith on Sep 8, 2016

Implicit returns are consistent with loops being array comprehensions and branches being conditional expressions. It's all recursive too; if a function ends on a branch that ends on a loop, the function will return the array from the loop.

It's part of the zen of CoffeeScript to always evaluate to the last thing evaluated.

Of course, we all establish idioms to improve our code and naturally assume it would be nice if they were baked in, but removing implicit returns from CoffeeScript is probably too uncharacteristic to make an argument based on practicality, unless the benefits are really substantial. Being able to omit a few return statements isn't much of a win.

coffeescriptbot commented 6 years ago

From @carlsmith on Sep 8, 2016

Didn't mean to be rude to anyone. I would like things slightly different myself, but it seems like a bridge too far. I can't see us actually developing a version of CoffeeScript without implicit returns anytime soon. Perhaps some clever syntax to explicitly change the behaviour would fly, but nothing proposed in previous discussions was very well received.

coffeescriptbot commented 6 years ago

From @lydell on Sep 8, 2016

Well said, @carlsmith. I agree.

coffeescriptbot commented 6 years ago

From @rattrayalex on Sep 8, 2016

Thanks for the terrific input all.

I'm closing this for now as any serious modifications to the language unrelated to ES6 are looking out of scope at this point.

coffeescriptbot commented 6 years ago

From @GeoffreyBooth on Sep 8, 2016

Yeah. At this point changing core, widely-used parts of CoffeeScript I think is probably off the table. Too many old stackoverflow posts would be no longer valid, and people would have no idea why. For better or worse, CoffeeScript is a victim of its own success.

coffeescriptbot commented 6 years ago

From @rattrayalex on Sep 8, 2016

It's probably worth closing several other, similar threads at this point. This project started with a broad possible range of focus areas and now that we've narrowed it down it probably makes sense to tie off several conversations.

@GeoffreyBooth, would you like me to take that on?

coffeescriptbot commented 6 years ago

From @GeoffreyBooth on Sep 8, 2016

@rattrayalex Sure. I think weโ€™ve reached consensus on preserving as much backwards compatibility as possible, so freewheeling discussions of major syntax changes or potential new languages should probably happen elsewhere.