guardArgs = (def, args) ->
i = 0
for arg, type of def
throw new Error("bad type of #{arg}") unless typeof args[i] == type
i++
typeEnsure = (def, f) -> ->
guardArgs(def, arguments)
f.apply @, arguments
myFunc = typeEnsure {name: 'string', i: 'number'}, (name, i) ->
console.log name, i
myFunc("foo", 1) # ok
myFunc("foo", "x") # Error: bad type of i
I think this can be extended to custom types too.Contracts For CoffeeScript
31–36 of 36 posts
Re: Contracts For CoffeeScript
#32Can't this be implemented as a DSL? https://gist.github.com/1180516 guardArgs = (def, args) -> i = 0 for arg, type of def throw new Error("bad type of #{arg}") unless typeof args[i] == type i++ typeEnsure = (def, f) -> -> guardArgs(def, arguments) f.apply @, arguments myFunc = typeEnsure {name: 'string', i: 'number'}, (name, i) -> console.log name, i myFunc("foo", 1) # ok myFunc("foo", "x") # Error: bad type of i I t…
Second, you need proxies to handle things like functions and mutable arrays.
Third, that there's a DSL for describing contracts is, I think, a large part of the point.
Re: Contracts For CoffeeScript
#33the CoffeeScript version is nice though :D
Re: Contracts For CoffeeScript
#34 f :: ((Num) -> Bool, Num) -> Bool
The type of f is not particularly obvious to me; instinctively, it could either be:1. A function that takes (a function from Num to [Bool, Num]) and returns Bool, or
2. A function that takes (a function from Num to Bool) and a Num, and returns a Bool.
Given enough time, I'm going to guess 2, but this makes CoffeeScript's destructing assignment, IE
[a, b] = func()
feel less 'first class'. Is this a serious ambiguity, or just me not having enough experience with precedence in CoffeeScript/functional languages?Re: Contracts For CoffeeScript
#35Higher order functions: f :: ((Num) -> Bool, Num) -> Bool The type of f is not particularly obvious to me; instinctively, it could either be: 1. A function that takes (a function from Num to [Bool, Num]) and returns Bool, or 2. A function that takes (a function from Num to Bool) and a Num, and returns a Bool. Given enough time, I'm going to guess 2, but this makes CoffeeScript's destructing assignment, IE [a, b] = fu…
f :: ((Num) -> [Bool, Num]) -> Bool
DaveRe: Contracts For CoffeeScript
#36Earlier quoted context omitted.
Not hardly. The runtime can detect that a function invocation violates a post-condition only after all of that function's side-effects have been run.
I believe jashkenas' example defines both a pre-condition and a post-condition, specifying that f accepts only odd numbers and returns only even numbers ('!' here is the operator for new contract, rather than logical negation). If f is called with anything other than an odd number, an error will be thrown right away, before the body of the function is run.
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)
}