Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to put a contracts on a hashmap's keys and values #42

Open
TobiaszCudnik opened this issue Apr 4, 2012 · 8 comments
Open

How to put a contracts on a hashmap's keys and values #42

TobiaszCudnik opened this issue Apr 4, 2012 · 8 comments

Comments

@TobiaszCudnik
Copy link

How to put a contracts on a hashmap's keys and values, for example custom key contract and object values.

Right now it's achivable via a custom function contracts which:

  • assets it's an object
  • checks all keys via object.keys()
  • checks all values in a loop using a custom object contract

Is there/will be a syntax for this? How about contract parameters? Maybe

foo :: HashMap TMyKey, TMyObjValue

Or

foo :: { @TMyKey, TMyObjValue }
@disnet
Copy link
Owner

disnet commented Apr 4, 2012

Don't have syntax for this right now. Closest I think is something like this:

class HashMap
  # non-implementation of a HashMap :)
  get: (key) -> @[key]
  put: (key, val) -> @[key] = val


HashMapC = (keyContract, valContract) ->
  ?{
    get: ((keyContract) -> valContract)
    put: (keyContract, valContract) -> Any
  }

StrHashMap = HashMapC Str, Str

f :: (StrHashMap) -> Any
f = (map) ->
  map.get 4

m = new HashMap

m.put 4, "the number four"
f m # contract violation...

Does this match with what you've been trying?

We definitely need some nicer syntax for stuff like this. I'm leaning towards the parameterisation approach (foo :: MyContract T, V) over a specific new syntax just for HashMaps.

@gregwebs
Copy link

gregwebs commented Apr 5, 2012

I think the problem I was just going to open up a ticket for is somewhat related. I am extending backbone views and models. The preferred way of doing this is

View = Backbone.View.extend
    method: (args) ->

So all the methods are defined in a JSON style. It isn't obvious to me how to add a contract. I can define the method externally, but that leads to some duplication. Perhaps I should add it on after extending?

@disnet
Copy link
Owner

disnet commented Apr 8, 2012

I think you should be able to do something like:

View :: { 
  method: (C) -> C 
}
View = Backbone.View.extend
  method: (args) -> ...

@gregwebs
Copy link

gregwebs commented Apr 9, 2012

yeah, I know I should be able to do that but then my type definition would be far away from the function location. Backbone views can easily take up 100 lines of code.

@disnet
Copy link
Owner

disnet commented Apr 9, 2012

Ah, I see. Yeah, there's probably not a great way to do it at the moment.

I'd like to add the ability to define inline contracts with object literals. So one could write:

obj = 
  (Str) -> Str
  meth1: (x) -> ...

  (Num) -> Num
  meth2: (x) -> ...

  Num
  x: 42

This is related to adding support for classes since the grammar here is pretty similar. Hopefully I'll have some time soon to crank this out :)

But this still wouldn't entirely solve your backbone example. If we added inline contracts or tried this today:

spec :: { method : (C) -> C }
spec = { method: (args) -> ... }

View = Backbone.View.extend spec

so the object we pass View.extend is wrapped in a contract. Depending on exactly how extend works you might not get what you expect because there's a conceptual mismatch going on. We really want to put a contract on View not the bit of data (spec) that is used to generate View.

Not sure the best way to address this.

@gregwebs
Copy link

method :: (C) -> C
method = (args) -> ...

# create a new copy and manually add methods
View = Backbone.View.extend {}
mkView = () ->
  v = new View
  v.method = method

# call to the outside function
View = Backbone.View.extend
  method : (args...) -> method(args...)

These seem like the only approach where I get a contract next to my function and place the contract on the correct object.
Second seems preferable.

@gregwebs
Copy link

This seems to work well. A small amount of manageable boilerplate. I need the context, though, so it looks like:

View = Backbone.View.extend
  method : (args...) -> method(this, args...)

I could apply the context (and maybe I will in the future), but I actually kind of like passing it around.

@gregwebs
Copy link

The style I am using now is

addContractMethods = (singleton) ->
  singleton.method :: (Str) -> Any 
  singleton.method = (str) ->

mkClass contractMethods

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants