Live data from Hacker News

Contracts For CoffeeScript

disnetdev.com

31–36 of 36 posts

Re: Contracts For CoffeeScript

#31
Can'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 think this can be extended to custom types too.

Re: Contracts For CoffeeScript

#32
post #31

Can'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…

First, I don't think what you show is a DSL -- it's just some functions. Rather, what Tim has implemented is a DSL.

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

#34
Higher 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] = 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

#35

Higher 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…

No ambiguity; if you put brackets around it you get a tuple (really, an array of fixed elements), and without brackets, the comma is part of the function signature. If you wanted to express your interpretation #1 you'd write:

    f :: ((Num) -> [Bool, Num]) -> Bool
Dave

Re: Contracts For CoffeeScript

#36
post #12
post #5

Earlier 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.

How is this different than creating an OddNumber and EvenNumber type that check their input in the constructor at run-time? That is the point of a type system.

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)
   }
Post reply on HN