Skip to content
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

Enhancements to the class keyword #279

Closed
lukesutton opened this issue Mar 24, 2010 · 12 comments
Closed

Enhancements to the class keyword #279

lukesutton opened this issue Mar 24, 2010 · 12 comments

Comments

@lukesutton
Copy link

I’ve been experimenting a little bit lately with using CoffeeScript’s classes, but I have unfortunately one behaviour which is a bit limiting

The class keyword allows you to define the constructor and functions to be attached to the prototype, but it doesn’t offer any way to attach functions to the object itself.

For example if I wanted to implement something like a class method I currently have to directly define it as a property on the object:

class Foo
Foo.bar: ->
  puts 'bo!'

It would be nice if CoffeeScript could provide some shortcut to doing this, rather than having to repeatedly type Foo.

@weepy
Copy link

weepy commented Mar 24, 2010

There was a discussion about this in an earlier ticket relating to executable class bodies.

It was discounted, but perhaps a similar possibility to support both would be to use the @ for prototypical methods and without for class methods:

class Animal
  constructor: (name) -> 
     @name: name
     Animal.all.push @ 
  @greet: -> 
     alert "hello $@name"
  all: []  
  count: -> all.length

@runeb
Copy link

runeb commented Mar 24, 2010

I think prototypical methods are more common. Less typing for the common case would be nice, although @ reads quite well.

@lukesutton
Copy link
Author

weepy: that would be perfect I think, although I agree with runeb; better to favour the common case.

@matehat
Copy link
Contributor

matehat commented Mar 25, 2010

Also, in ruby-style class body, self is defined as the class itself, not the instance, and it does make sense.

@weepy
Copy link

weepy commented Mar 25, 2010

it does make sense - in ruby, but JS is a bit different. it would be confusing to swap the position of the @'s ala ruby style.

@matehat
Copy link
Contributor

matehat commented Mar 27, 2010

Well, since the construct (and the keywords used) suggest we are acting on a class, rather than on a prototype, a keyword like @ to refer to the class itself isn't a bad idea I think.

Also, since we'd used them a lot less often than when defining methods for instances, I think @ for those cases would get awkward after some time.

@weepy
Copy link

weepy commented Mar 28, 2010

Perhaps it would be better to use the :: to avoid confusion with this. E.g.

class Animal
  constructor: (name) -> 
     @name: name
     Animal.all.push @ 
  ::greet: -> 
     alert "hello $@name"
  all: []  
  count: -> all.length

@matehat
Copy link
Contributor

matehat commented Mar 28, 2010

:: refers even more explicitly to the prototype itself than to the class

@weepy
Copy link

weepy commented Mar 28, 2010

Yes - it does - so meaning here is :: for instance methods.

@matehat
Copy link
Contributor

matehat commented Mar 28, 2010

ahh yeah, right, ignore my last comment. Anyway, that's really close to the way it was before the class keyword was introduced. Also, due to the js own prototype-based paradigm, we tend to not refer to base classes (read fictive base class) directly so often. So I don't know if those rare case warrants such a change from the current statu quo.

@jnicklas
Copy link

This is very close to my original suggestion in the executable class bodies ticket, my suggestion was to add :: as a general shortcut to this.prototype, that way the class body is run inside a closure, where this points to the class. This way we can add class variables/methods through @ and locals without a prefix:

class Animal
  @all: []  

  ::constructor: (name) -> 
    @name: name
    Animal.all.push @ 

  size = @all.length
  if size > 5
    ::greet: -> alert "hello $@name"
  else
    ::greet: -> alert "too many animals!!"

(function() {
  this.all: []  

  this.prototype.constructor: function(name) {
    this.name: name;
    Animal.all.push(this);
  };

  size = this.all.length:
  if size > 5 {
    this.prototype.greet: function() { alert("hello $@name"); };
  } else {
    this.prototype.greet: function() { alert("too many animals!!"); };
  }
}).call(Animal)

I still think it's kinda neat. Especially since there's a zen-like no-magic thing to this, everything is just a closure. But the ::foo: syntax looks a little odd and the classes are already well established in CS now, so I don't think it's a good idea to change this.

@jashkenas
Copy link
Owner

Alright, we now have class (static) properties as part of the class definition, if you want them, on master. Just use the @property syntax to mean "add the property directly to this class". So:

class Example

  instance_method: ->
    "I'm an instance method."

  @class_method: ->
    "I'm a class method."

It works the same way for properties as well. The compiler is now using it, but it's only needed in a small handful of places in the codebase. Closing the ticket.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants