Skip to content

Instantly share code, notes, and snippets.

@josher19
Created January 11, 2010 11:23
Show Gist options
  • Save josher19/274170 to your computer and use it in GitHub Desktop.
Save josher19/274170 to your computer and use it in GitHub Desktop.
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