Comments (35)
I'm strongly in favor of solution 3. Would be great to have the same functionality as in JS. And I like your way of coding it better than I did mine...
from coffeescript.
Solution three is a beautiful idea. I don't fully understand its mysteries, because I can't seem to implement it. Simple cases like yours work fine, but the tests fail completely -- I think wrapping it in a closure doesn't inherit the prototype chain of the inner class.
If you think you can help, check out the "fix_new" branch, and try to fix the tests ("rake test"), or let me know what you think is going wrong.
from coffeescript.
is there a way of getting tests to say what failed ? Right now all I've got is
1) Failure: test_execution_of_coffeescript(ExecutionTest) [./test/unit/test_execution.rb:17:in `test_execution_of_coffeescript' ./test/unit/test_execution.rb:13:in `each' ./test/unit/test_execution.rb:13:in `test_execution_of_coffeescript']: is not true.
and a narwhal error
TypeError: Cannot find function func in object [object Object]. (/Users/jonahfox/src/coffee-script/lib/coffee_script/narwhal/lib/coffee-script.js#67(eval)#1)
from coffeescript.
The code I initially wrote was just an idea. Here's some code that actually works :
A = function(x,y) { return this.array= [x,y] } A.prototype.sum = function() { return this.array[0] + this.array[1] } a = new A(1,2) console.log(a) // => [1,2] var klass_constuctor = function(klass) { var constr = function() { var args = Array.prototype.slice.call(arguments,0) klass.apply(this, args) } constr.prototype = klass.prototype return constr } _A = klass_constuctor(A) _a = new _A(1,2) console.log(_a, _a.array, _a.sum()) // => object Array, [1,2], 3
from coffeescript.
just realized that that isn't going to work very well. further operations to A won't get applied to _A, and any properties are A aren't currently get applied. There are work arounds, but I don't recommend this route now.
"==>" FTW
from coffeescript.
ok so how about this !
A = function(x,y) { var ret = this.array = [x,y]; if(arguments.callee != this.constructor) return ret } new A(1,2); // => Object array=[2] A(1,2) // => [1,2]
from coffeescript.
Cool idea, but there are two problems -- we'd have to do the check for every function (distasteful), and arguments.callee is deprecated in ECMAScript 5.
from coffeescript.
Solid. I've been poking around with the code, too, because there's got to be a way to do this! Your code looks pretty good, though it prevents constructors from ever returning a value. This seems like a fine tradeoff since I'm not sure when a constructor would ever not return 'this'. And even if there's some bizarre little corner case, CoffeeScript can reflect the 99.99% case rather than adopting weirdness in order to support the 0.01% case.
Doh. Just saw Jeremy's note... But we're on the right track.
from coffeescript.
ok then ! We're saved by our named constructor
A = function A(x,y) { var ret = this.array = [x,y]; if(A != this.constructor) return ret }
Doesn't fix the check for every function though. Could have a keyword to skip it if you were concerned about performance ??! Eg: fast_square: x ==> x*x
from coffeescript.
Nice, the idea of adding this check, only when the first letter of the function name is capitalized, is awfully appealing.
from coffeescript.
high five to that ! So the upshot of that would mean that :
- You can have functions with capital letters if you want.
- constructors without capital letters 'might' break (if last return value is array or object), so should be avoided ?
from coffeescript.
[doh... gotta be faster with my comments!]
Looks as we should be okay, though. I've added uniqueifying stuff to the function name.
function __coffee_script_construct_A(x, y) { var ret = this.array = [x, y]; if (__coffee_script_construct_A != this.constructor) return ret; }
The check is distasteful, but doesn't have much effect on performance (1000000 new instances => 15s without, 17s with check).
Weepy: good stuff.
from coffeescript.
Weepy:
- Yep, functions with capital letters wouldn't break, they'd just get an extra check.
- It can be a CoffeeScript convention to have constructors start with capital letters -- it's already good style, and this is just extra incentive to use it.
from coffeescript.
FWIW: I really don't think that the little check is an issue. It's a teeny price to pay to keep JS and CS aligned. There's no performance difference (on FF 3.7a) for this simple test case. My vote would be to add the check to every function.
Also, recall that kamatsu uses lower case constructors and isn't alone.
http://github.com/jashkenas/coffee-script/issues/#issue/17/comment/100320
http://github.com/jashkenas/coffee-script/issues/#issue/17/comment/100664
http://github.com/jashkenas/coffee-script/issues/#issue/17/comment/100721
from coffeescript.
Yeah, I'm a bit torn about it, but you won't need it on 95+% of functions, and while the performance isn't a problem, the code clarity is a problem, and the code-size bloat is a real problem for JavaScript.
from coffeescript.
You'd still be able to use other libraries that had constructors that are lowercase. It's a good pattern anyway to use capital letters for constructors and as it's new code that you'd be writing, I don't think others would particularly have a problem with it.
from coffeescript.
I'm a fan of constructor:
- It's explicit, much more apparent to new Coffee users what's going on.
- It's good to know when a function should be used with new, instead of called directly
- I think that ==> is dangerous even for experienced Coffee users, as it doesn't necessarily distinguish itself from => when scanning code.
- If users want to use custom functions as constructors in a non-standard way, they can still explicitly return the object
- It doesn't rely as much on magic
from coffeescript.
Alright, this is now resolved on master. I don't think that it's worth tagging a function with a long word ("constructor"), just to avoid writing a short one ("this"). But I do want to protect folks from mysterious errors when constructors work improperly, so master now has weepy's special check added to functions that start with a Capital Letter:
Horse: name => this.name: name
Into:
Horse = function Horse(name) {
var __a;
__a = this.name = name;
return Horse === this.constructor ? this : __a;
};
Closing the ticket... If you'd like to use lowercase constructors, against the style convention, just put a this
at the end.
from coffeescript.
Right, I am going to make a branch that un-does this feature as I feel it to be against the spirit of this language.
We should under no circumstances affect dynamic semantics by enforcing a naming convention.
Introducing a style convention on top of existing JS style is something I would oppose strongly.
from coffeescript.
This is where you are compensating for one divergence from JS semantics (implicit return) with another massive divergence from JS semantics (adding checks to capitalized functions), when you could just add a feature that makes it convergent again, such as a keyword.
from coffeescript.
The divergences from JS semantics are all pointing in the same direction --> everything should be usable as an expression, to the greatest extent possible. I agree with you that the most distasteful part of this "fix" is the capital-letter sniffing. Are you proposing the constructor
keyword, which just suppresses the implicit return, or simply having a CoffeeScript convention of placing a this
as the last line of constructor functions?
from coffeescript.
hm, I agree that constructor is sort of ickishly long, but seeing as significant indentation lends itself to top-heavy declarations, I would prefer to have a keyword at the top rather than have to stick a weird value at the bottom.
It still doesn't sit right with me, but i'd go with constructor
, but keep options open for changing that in the future.. there has to be a better, terser notation for it, but the only thing I can think of is changing the => operator to something else for constructors, which is arguably worse
from coffeescript.
(by the way, i am kamatsu, i changed my username)
from coffeescript.
My problem with constructor
:
Tortoise: How do you create a constructor function in CoffeeScript?
Achilles: As in JavaScript, any function can be used as a constructor ...
but you should probably tag the function declaration with the
"constructor" keyword.Tortoise: Why?
Achilles: Well, you don't really need to use it, unless your constructor
returns an object that isn'tthis
. If you return another object, then you're
not going to get the instance you expect when you callnew func()
Tortoise: So I could just return
this
myself, and it would work.Achilles: Yes.
Tortoise: So what's the point of having the "constructor" keyword?
Achilles: So that everyone doesn't have to have this conversation.
It's a keyword that's like bubble wrap. It only makes sense to use when you don't understand what's going on. If you understand the JavaScript, you'll probably prefer to return this
yourself.
from coffeescript.
My big beef with 'constructor' is that it's error prone. Forgetting to use the notation will lead to nasty, hard-to-find bugs.
Again, I advocate for adding the 'new' check to every function... It will increase the JS slightly, but it'd make the CS and JS behavior pretty much identical.
from coffeescript.
Reopening this ticket because it needs some more thought. I'm ever-more-often running into situations where the constructor safety check doesn't work successfully, and am starting to think that we either need to make it bulletproof, or just ditch it and say that you always have to put this
as the last line of a constructor.
My use case is this quickie inheritance helper function that I'm using for the CoffeeScript-in-CoffeeScript code generation (del
is a delete function that returns the value):
inherit: (parent, props) ->
klass: del(props, 'constructor')
klass extends parent
(klass.prototype[name]: prop) for name, prop of props
klass
Which lets you define subclasses without having to repeatedly assign to the prototype, like so:
CallNode: inherit Node, {
constructor: (variable, args) ->
...
compile: (options) ->
...
}
But those constructors, sadly, don't get the check, even though they wind up with a capitalized name in the end. I'm leaning towards removing the check -- we've exhausted the options pretty well in this conversation so far -- what do y'all think?
from coffeescript.
I agree
from coffeescript.
Seems reasonable - in which case, it comes down to education. For advanced users, in fact you only need to return something that's not and object or an array. But I think returning this
makes sense for a constructor - so we should push that message.
from coffeescript.
Just throwing ideas here: how about making extends
behave in this manner:
B extends A: (name) ->
@name: name
super # Calling and returning value from parent's constructor
should compile to this:
var B;
B = function B(name) {
this.name = name;
return A.call(this);
}
B.__superClass__ = A.prototype;
B.prototype = new A();
B.prototype.constructor = B;
when you want a prototype that doesn't extend another class, you would still use:
A extends Class # built-in keyword
should compile to:
var A;
A = function A() {
return this;
}
and optionally to define a constructor, in which case you must return this
:
A extends Class: ->
@initialized: 1
@
A::move: -> alert('Moving, a moment please...')
should compile to (something like):
var A;
A = function A() {
this.initialized = 1;
return this;
}
A.prototype.move = function move() {
return alert('Moving, a moment please...');
}
So to sum it up, a new way to define prototype objects where Coffee will always return this
when a constructor was not given. When one is available, as per weepy's comment, you must know what you are doing.
from coffeescript.
Why must "Class" be a built in keyword? And why use "Class" when it is not a class at all but an object?
from coffeescript.
I don't really understand what you've achieved. You still have to drop in a this
when there's no extension, and
A extends Class
is exactly the same as
A: -> this
is it not?
Am I missing something?
from coffeescript.
@Tesco: what I am trying to archive is to make it explicit. When it is explicit, you know what to watch out for, i.e., the return this
at the end. This should make it easier for Coffee to figure that out too.
@liamoc: I realise that, just trying to make it more convenient for people that are not used to prototype based programming. A lot of my colleagues and friends still think JavaScript is a true OO language.
From both of your comments, I gather the idea wasn't well received, but then again, reason it's called an idea, Lol.
from coffeescript.
Making things more convenient? Or more confusing? Trying to hide JS's prototypal nature will only make things worse. Also, prototypal OO is in no way not a "true OO" paradigm. It's been around since about as long as the class approach.
from coffeescript.
Stan -- It's a nice idea, don't worry about it. This is why it's great to have folks from different backgrounds contributing to the language, to see proposals with different flavors.
I've removed the safety check on master, which may break your current code, so be careful. There was only a single test to fix (and it was testing inheritance anyway), so it probably won't be too difficult to upgrade.
I think that the new party line should be something like: In CoffeeScript, functions return their values. When you're writing a constructor, make sure to return the new instance of the object.
Node: (children) ->
@children: children
this
Which will be documented. Closing the ticket...
from coffeescript.
As of Issue #210, CoffeeScript has classes.
from coffeescript.
Related Issues (20)
- Unnecessary `splice` ref added for Array destructuring with rest element not in last position HOT 4
- Bug: Re-ordered nested non-end BindingRestElement doesn't get transpiled HOT 1
- CoffeeScript is fantastic, please donβt give it up HOT 1
- How to imitate `let` behavior in loops? HOT 5
- Proposal: Alternative file extension HOT 1
- Bug: Excessive variable and shallow copy for leading or middle rest parameter
- Proposal: Introduce `let` statement. HOT 6
- Proposal: Document Existential Operator Assignment
- Site issue: code blocks twitch on hover HOT 2
- Proposal: cake command should support ES6 modules HOT 2
- Need help understanding class member meanings HOT 1
- CLI `npm` `scripts` and input `.coffee` file/s as last argument conflicting with `--watch` HOT 2
- Bug: wrong code is transpiled for function call without parentheses HOT 2
- Proposal: Add end word to close method or class HOT 2
- Bug: Invalid indentation allowed after `do`
- Bug: Remove checkShebangLine multi arguments check HOT 1
- feature_request(html): backend CoffeeScript compilation inside HTML files HOT 3
- Bug: yield cannot be used in do -> expressions reliably? HOT 5
- [not an issue] An embeddable playground for CoffeeScript HOT 1
- Please help HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from coffeescript.