-
Notifications
You must be signed in to change notification settings - Fork 2k
Named Closures #2205
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Comments
Not possible in pure coffescript. It was removed because of some leakage in ie or so. See #15. |
Yep, there's no need for NFEs, so we don't have them. Closing. |
They are useful for debugging purposes, so, there is need for them. |
+1 |
2 similar comments
+1 |
+1 |
Hmmm.. this is quite interesting, if the function are attached directly to a variable (i.e. = ), then Chrome infers and shows nice names for the functions on the stack trace: foo = ->
bar()
bar = ->
throw 'Yo, look at the stack trace!'
foo()
# Uncaught Yo, look at the stack trace!
# bar
# foo
# (anonymous function)
# CoffeeScript.run
# b
# window.undefined.runScripts But as soon as you change the assignment and let the function first go into another function, then the names are not inferred, which seems reasonable: id = (x) -> x
foo = id ->
bar()
bar = id ->
throw 'Yo, look at the stack trace!'
foo()
# Uncaught Yo, look at the stack trace!
# (anonymous function)
# (anonymous function)
# (anonymous function)
# CoffeeScript.run
# b
# window.undefined.runScripts Now, as i understand from this article, it should be possible to name anonymous functions using the named = (name, fn) ->
fn.displayName = name
fn
foo = named 'myFoo', ->
bar()
bar = named 'myBar', ->
throw 'Yo, look at the stack trace!'
foo()
# Uncaught Yo, look at the stack trace!
# (anonymous function)
# (anonymous function)
# (anonymous function)
# CoffeeScript.run
# b
# window.undefined.runScripts Maybe Well... i was just going to propose using |
"there's no need for NFEs", yet, according to the documentation:
Because only constructor functions need helpful stack traces? Probably one of the most asked-for features: #15 #2947 #3046 #1640 #2666 #2152 IMO named functions is an important JavaScript feature and CS is crippled without it... |
That's not how it works -- try it. The last time I checked in Chrome, the debugger is able to infer the name of every function, but anonymous classes it was unable to. For that reason, CoffeeScript stack traces should appear complete, and completely named. |
How is Chrome able to get function names of unnamed functions?
should compile to
How can Chrome give the anonymous function a name?! |
Like I said -- try it. You'll be pleasantly surprised. |
Well, VisualStudio 2012 doesn't and its all I care about since I use CS to develop Windows Store apps. What is chrome spitting out as the function name? Why is this feature debated so long? |
@pke how else will we track the IP's in real time? http://www.youtube.com/watch?v=hkDD03yeLnU |
I keep hearing "it's just JavaScript" from various peers, but apparently CS is more like a subset of JavaScript. (I know, "the good parts"...) Putting the blame/responsibility on language vendors (Chrome) doesn't really address this missing feature. I think part of the misunderstanding here, is that there are actually two varieties of In other words - expression form is good:
And statement-like form is good:
Notice how you don't need the semi-colon at the end. The following form is bad:
Note the semi-colon at the end, which terminates the I'm not asking you to put that feature in CoffeeScript. But I know you want everything to be an expression, but not every function is an expression - sometimes a function is just a function. How about introducing a statement and keyword for named functions? e.g.:
Also this improves upon the confusing semantics of JavaScript where Thoughts? |
For that matter, named functions declared as functions (rather than variables) should probably be immutable - so |
Note the description of semantics in the ECMA-262 (5.1) Function Specification which defines two different productions, FunctionDeclaration and FunctionExpression, which have identical syntax, but different semantics. FunctionDeclaration and FunctionExpression with no Identifier are both straightforward, but notice the lengthy description of FunctionExpression with the Identifier - no wonder the language vendors get this one wrong ;-) |
Mmm... i think that, as long as we're supporting IE <= 8, there's no other reasonable option than what the current implementation does. Introducing a new syntax to generate JS function declarations, thus increasing the language's complexity by having yet another way of defining functions and adding all the function hoisting nonsense to CoffeeScript, just for better stack traces is a no-go IMHO. Compiling all functions to named function expressions (or, at least, all functions assigned to a variable) would be a reasonable alternative, if it weren't for stupid IE <= 8 behaviour, which clearly violates the spec that @mindplay-dk linked:
So, unless i'm interpreting things the wrong way here, i think we're stuck with current semantics unless we decide to ignore IE <= 8. Are the better stack traces the only advantage of having named functions? |
See michaelficarra/CoffeeScriptRedux@45c5d56 and the related discussion for ways to work around that IE<9 bug. |
I used
We can introduce "--fuck-ie8" compiler option (which I would very much use as a default because I develop for node/v8 only and don't see any reason why IE should have any impact whatsoever on syntax of my node.js code)
I think so. It is a reason enough though. |
What's the point? How is that different from
Not bad, but it does clutter the local scope with what is most likely unused variables - unless you do it inside throw-away one-shot closures as suggested by @michaelficarra above. Which is also not bad, it's just... odd... Sticking to "JavaScript, the good parts" usually means playing avoidance, and the odd/complicated semantics of the contrived function-declaration-expression doesn't strike me as one of the good parts. I don't know, I'm probably just obsessing about details as usual... |
@mindplay-dk cluttering the what now? Not so. The name in an NFE is just the function's
|
It's different in that it doesn't hoist the function definition up into the enclosing scope: console.log(x); // -> undefined
var x = function x() {}; At least, that the expected behaviour (which IE <= 8 breaks).
Yeah, it is a very valid practical reason. I was just curious to know if there were other, more fundamental reasons, why using only anonymous functions was wrong. Oh, i had totally forgotten about that discussion. Yeah, so another alternative, that would allow us to use named function expressions and not screw up on IE <= 8, would be generating a fresh name for the function expression. I'm not sure if the current compiler is up for that hehe. Still, i'd really like to see practical example of when stack traces could be improved by using named functions. The OP shows an example of using a named function as a callback for an asynchronous operation, but a normal variable can be used if we want to have the function name in the stack trace: $('button').on 'click', myClickHandler = ->
throw new Error 'boom'
# When clicking the button (on Chrome dev tools):
# Uncaught Error: boom
# $.on.myClickHandler
# jQuery.event.dispatch
# elemData.handle (jsFiddle) |
I agree with the poster, we need a way for named closures, not just for stack analysis but also for heap profile analysis. This image is taken from google citation source (see below the containment image for the tip) Maybe a no-space op like namedClosure->
x = 10
y = 1
return or ->namedClosure
x = 10
y = 1
return |
I would say there will be a quite a huge need for NFE now; http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/#disqus_thread |
Sure, IE had this for some time now and it's really annoying that CS doesn't support named anon functions. |
There's another advantage that hasn't been mentioned: When pretty printing CoffeeScript objects, it's nice to have the names of the functions, like |
It does indeed. In case other people are wondering what @jashkenas is referring to, this is the syntax to use:
instead of the simpler:
Results: For those browsers or dev tools that don't infer the name, CS could just recognize such an assignment of a lambda to a name (or to a constant object property, while we're at it) and give the same name to the JS function definition. This would solve the problem for 99% of use cases while not changing a comma of CS syntax. |
We put that in a fork a year ago, I am surprised this is still debated here. |
Here a non debug scenario where it could be useful: EventEmitter = (require('events')).EventEmitter;
var e1 = new EventEmitter();
e1.on('event', function onEvent() {
console.log('e1 event!');
return e1.removeListener('event', onEvent);
});
e1.emit('event');
e1.emit('event'); Of course it's not too complicated to put it in a var, but I find it less elegant in this case. |
@forty, why do you find it less elegant? I think it's just the same: {EventEmitter} = require 'events'
e1 = new EventEmitter
e1.on 'event', onEvent = ->
console.log 'e1 event!'
e1.removeListener 'event', onEvent
e1.emit 'event'
e1.emit 'event' The only difference being that the Off-topic: even in this little example, the difference in punctuation noise between JS and Coffee is quite stark! I really like that 😸 |
Not so much. This is the javascript for you: var {EventEmitter} = require('events')
var e1 = new EventEmitter
e1.on('event', () => {
console.log('e1 event!')
e1.removeListener('event', arguments.callee)
})
e1.emit('emit')
e1.emit('emit') Once people learn to get rid of those noisy and pointless semicolons and v8 implements proper es6, js code gets much cleaner. |
@epidemian I did not though of using an assignment as an argument, I like it in this case. Note that the code in my previous comment was originally coffee output so it's probably a bit more verbose than hand written javascript. Thanks for you answers! |
Let's say we want to do this:
Instead of this:
How is that possible in CoffeeScript?
The text was updated successfully, but these errors were encountered: