isEven = (x) ->
x % 2 is 0
f :: (!isOdd) -> !isEven
f = (x) -> ... isEven = (x) ->
x % 2 is 0
f :: (!isOdd) -> !isEven
f = (x) -> ...There are good uses for static type checkers and design by contract, but neither one is a good substitute for the other.
They both work to enforce program invariants and there's a large overlap in the invariants they can express. Usually contracts are checked dynamically (as in contracts.coffee) but this is not a hard requirement (for example .net's code contracts can be statically checked [1]).
isEven = (x) -> x % 2 is 0
isOdd = (x) -> x % 2 isnt 0
addEvens :: (!isEven) -> !isOdd
addEvens = (x) -> x + 1
I am guessing that both '!'s define a new contract - and also guessing that coffeescript does not actually have a '!' operator for logical negation. So that addEvens simply takes an even number and returns an odd number.I find it confusing that the different syntax highlighting of the two '!' suggests (wrongly) that they have different meanings. Also, logical negation is something often used with isOdd/isEven functions.
• Indentation shifts mean different things depending on context (could mean we're doing an object literal, could mean we're defining a function, could mean we're entering a loop, etc.)
• Looping through arrays uses "in" while looping through everything else uses "of"
• Array and object literal syntax might create arrays and objects or define variables depending on which side of the equals sign you're reading
Scala can make this really transparent and concise using an abstract class to implement most of the plumbing and implicit type conversion to automatically convert the contract enforcement types to and from the native types.
case class EvenNumber(val x: Int) extends Contract[Int] {
require(x % 2 != 0)
}To quote Jeremy Ashkenas's JSConf talk on forking CoffeeScript: "when in doubt, cheat." ;-P