contracts.coffee icon indicating copy to clipboard operation
contracts.coffee copied to clipboard

CoffeeScript classes supported?

Open TobiaszCudnik opened this issue 12 years ago • 9 comments

Are CoffeeScript classes supported? I didn't have any luck while trying to put a contract on a class in various ways. Maybe i'm doing something wrong?

Contract for a whole class:

NodeAddr = ? {
    port: Num
    host: Str
}
Node :: (NodeAddr, Any, Any) -> {
    address: (NodeAddr) -> Any
}
Node = class
    constructor: (address, services, next) ->
    address: (addr) ->

Results in

TypeError: Object.getOwnPropertyDescriptor called on non-object
    at Function.getOwnPropertyDescriptor (native)
    at Object.getPropertyDescriptor (...node_modules/contracts.js/lib/contracts.js:410:23)
    at Contract.handler (...node_modules/contracts.js/lib/contracts.js:853:25)
    at Contract.check (...node_modules/contracts.js/lib/contracts.js:597:21)
    at ...node_modules/contracts.js/lib/contracts.js:742:29
    at <error: illegal access>
    at <error: illegal access>
    at Object.<anonymous> (...prototypes/contracts/foo.coffee:71:9)
    at Object.<anonymous> (...prototypes/contracts/foo.coffee:86:4)
    at Object.<anonymous> (...prototypes/contracts/foo.coffee:87:4)

Contract for a specific method:

NodeAddr = ? {
    port: Num
    host: Str
}
class Node
    constructor :: (NodeAddr, Any, Any) -> Any
    constructor: (address, services, next) -> yes
    address: (addr) ->

Results in "Error: In foo.coffee, Parse error on line 29: Unexpected 'OUTDENT'".

TobiaszCudnik avatar Feb 24 '12 00:02 TobiaszCudnik

An unfortunate and glaring omission, we don't have explicit grammar support for putting contracts on classes yet. I really should have added them before, it's now at the top of my stack.

Interestingly enough, your first example of putting a whole contract on the class should have worked since Node compiles to a normal constructor and contracts work fine on them. Not sure yet what is causing the problem but I'll look into it.

disnet avatar Feb 24 '12 00:02 disnet

Thats a pity as my app is OO and classes was first place where i wanted to put the contracts. I'll be looking forward for them.

Thanks for a great library and idea. It'll be really powerful once used.

BTW tested on node 0.7.0 and 0.5.10, same results.

TobiaszCudnik avatar Feb 24 '12 09:02 TobiaszCudnik

After deeper checking there an issue with two things here:

  1. The -> wont work for classes, ==> need to be used.
  2. The following line:
address: (NodeAddr) -> Any

Changing NodeAddr to Any makes it all passing and class is initialized correctly.

TobiaszCudnik avatar Feb 24 '12 20:02 TobiaszCudnik

Interesting...

  1. The -> wont work for classes, ==> need to be used.

This is definitely a bug. The ==> contract is supposed to restrict the function it is guarding to only be used with new but -> should work for both new and non-new calls.

disnet avatar Feb 24 '12 20:02 disnet

I needed to use ==> because -> doens't trigger options.newSafe, thanks to which proxy returns new instance instead of a return value of the constructor.

Additionally, to have a class contracted fully, you have to do 2 things:

  1. Apply contract in the same file.
  2. Divide class contract to 2 custom ones: constructor and the instance body (object).
  3. Apply all instance body contracts onto the prototype, possibly using the following code:
# TServer is a contract
# Server is a class
for prop, Tcontr of TServer.oc
    continue if not Server::[prop] or
        prop is 'constructor'
    Server::[prop] :: Tcontr
    Server::[prop] = Server::[prop]

TobiaszCudnik avatar Mar 11 '12 22:03 TobiaszCudnik

Has there been any movement on this issue?

rimmington avatar Apr 12 '13 09:04 rimmington

Sorry, no. Haven't had time to work on this project in a while.

disnet avatar Apr 12 '13 19:04 disnet

+1 for this

benrudolph avatar Feb 21 '14 10:02 benrudolph

:+1: for class suppport!

DominikGuzei avatar Jan 03 '15 13:01 DominikGuzei