Created
January 11, 2010 11:23
-
-
Save josher19/274170 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
I have some suggestions for making CoffeeScript Classes even easier to use | |
in a friendly, "Unfancy" way. | |
First, is to have an easy way to give the default value. | |
Second, is a quicker way set my class variables: | |
this.var_name = var_name; | |
Third, is a "mustbe" clause which ideally would be checked at compile time instead of while running. | |
Fourth, some examples of how these changes will make the code more "Unfancy", readable, and less buggy. | |
1.) Allow a "default" in function args or ?? in expressions as a shortcut. | |
Existence (?) is great, but it can be even better if we can use it like the || operator. | |
speed default 45 | |
# is equivalent to any of: | |
speed ??= 45 | |
speed: speed ?? 45 | |
# should be currently supported | |
speed: if speed? then speed else 45 | |
// which in javascript would all become: | |
speed = (typeof(speed) !== 'undefined' && speed !== null) ? speed : 0; | |
which is much smarter way to do it than | |
speed = speed || 45; | |
Bug-prone CoffeeScript example: | |
Horse: name, speed => | |
this.name: name | |
this.speed: speed || 45 | |
deadHorse = new Horse("Gluey", 0); | |
"This horse has a speed of " + deadHorse.speed + "!" | |
# ... 45! | |
## See http://gist.github.com/274158 for more examples of common class parameter shortcut bugs. | |
Better CoffeeScript example: | |
Horse: name, speed => | |
this.name: name | |
this.speed: if speed? speed else 45 | |
Best, "Unfancy" CoffeeScript example: | |
Horse: name, speed default 45 => | |
this.name: name | |
this.speed: speed | |
2) A quicker way set my class variables would be using "my": | |
my: => this[attr]: attr | |
Horse: name, speed => | |
this.name: name | |
this.speed: if speed? speed else 45 | |
becomes a one liner: | |
Horse: my name, my speed default 45 => | |
It would be nice to have in the compiler so it works well with default: | |
MyClass: my _x default _y => | |
# is more or less equivalent to: | |
MyClass: _x => this._x : _x : _x ?? _y | |
# _y should not show up in this.arguments since it is usually a constant default value. | |
// in javascript becomes: | |
function MyClass(_x) { | |
this["_x"] = _x = (typeof(_x) !== 'undefined' && _x != null) ? _x : _y; | |
} | |
3) One thing that gets newbies and sometimes veteran Javascript programmers is giving the wrong type of | |
argument to a function or constructor. A common example is forgetting to convert user input in a textfield | |
from a String ("42") to a Number (42). A "mustbe" (throw Error) or "force" (try to convert to new Class) | |
clause, which ideally would be checked at compile time (against primitives, anyway) instead of while running | |
would be great! | |
# CoffeeScript: | |
Horse: my name mustbe "string", my speed default 45 force Number => | |
// javascript: | |
function Horse(name, speed) { | |
// name mustbe String | |
if (! isType(name, "string") ) throw new ArgTypeError(name, "string"); | |
// my name | |
this.name = name; | |
// speed default 45 | |
speed = (typeof(speed) !== 'undefined' && speed != null) ? speed : 45; | |
// speed force Number | |
if (! isType(speed, Number) ) speed = new Number(speed) ; | |
// my speed | |
this.speed = speed; | |
} | |
Sample Javascript and tests for ArgTypeError and isType are in this Gist: | |
http://gist.github.com/277078 | |
4) Extended CoffeeScript examples using proposed new syntax additions: | |
// See: http://gist.github.com/gists/274170 | |
Animal: => | |
Animal::move: meters => | |
alert(this.name + " moved " + meters + "m.") | |
Animal::toString => this.name || this.constructor || "ANIMAL"; | |
Veg: => | |
Veg::toString => "Veggies" | |
Mineral: => | |
Snake: my name => | |
Snake extends Animal | |
Snake::move: => | |
alert("Slithering...") | |
super(5) | |
Snake::eats: prey mustbe Animal => | |
if prey.speed > this.speed then | |
alert(prey + " escapes!") | |
else | |
alert([prey, "swallowed by",this.name].join(" ")); | |
Horse: my name, my speed default 45 force Number => | |
Horse extends Animal | |
Horse::move: => | |
alert("Galloping...") | |
super(this.speed) | |
Horse::eats: prey mustbe Veg => alert("chomp chomp"); | |
sam: new Snake("Sammy the Python") | |
tom: new Horse("Tommy the Palomino") | |
// sam.move() | |
// tom.move() | |
babyspeed: `$ && $('#speed').val();` # grab from user input, forget to convert to Number. | |
foal: new Horse("Baby Foal", babyspeed || "4") | |
grass: new Veg() | |
alert(getType(foal.speed)) # Number | |
tom.eats(grass) # chomp | |
sam.eats(tom) # tom escapes | |
sam.eats(foal) # gulp! | |
# won't work: | |
sam.eats(grass) # error! | |
tom.eats(sam) # error! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment