Branch-Hacking
This.
The SOPA/PIPA protests today were necessary but ultimately an exercise in branch-hacking. If SOPA is defeated it’ll be reborn in a year with a different name (just as PIPA is the new COICA).
It’s time to strike the root.
This.
The SOPA/PIPA protests today were necessary but ultimately an exercise in branch-hacking. If SOPA is defeated it’ll be reborn in a year with a different name (just as PIPA is the new COICA).
It’s time to strike the root.
An update to contracts.coffee (0.2.0) is now up on npm. I’ve fixed up a few bugs since the intial release and it’s now based on the latest CoffeeScript (1.2.0) but the big update is a rework of how modules are handled.
Before this update we were handling module blame tracking by forcing the programmer to call .use() before a contracted value could be used. This did the work of figuring out who the server and client module.
This was an awkward way to enforce a module pattern since not only do you have to write more code but it also means you have to know which values in a module have a contract. This breaks abstraction which is bad.
So with this latest update we’re completely dropping .use(). How we keep tack of the modules without it depends on whether you are using node.js or a browser.
If you are using node.js then the wiring is handled automatically by wrapping the require function and exports object. If you put a contract on an export value the correct server and client module names are recorded.
# file Math.coffee
exports.square :: (Num) -> Pos
exports.square = (x) -> x * x
#####
# file Main.coffee
{square} = require './Math'
# vioation blaming Main.coffee
square "a string"
You can also put a contract on a value that isn’t on the exports object (for use inside the module), but the module name might get confusing since it’s just the file name with “(value)” or “(caller)” appened. I will look at adding something like Racket’s nested boundaries to clean this up at some point.
If you’re using the browser, things are a bit more complicated. Since the browser environment doesn’t currently have a standard way to do modules, we’re stuck doing the wiring by hand. Details are in the documentation but the basic idea is that the library now provides Contracts.exports and Contracts.use which are used to construct contract aware modules.
Contracts.exports creates and names an exports object:
# Math.coffee
# create and name the exports object
exports = Contracts.exports "Math"
exports.square :: (Num) -> Pos
exports.square = (x) -> x * x
# put the exports object on the global object
# for other modules to see and use
window.Math = exports
And Contracts.use pulls in a module and names the user of the module.
# Main.coffee
{square} = Contracts.use window.Math, "Main"
square 4 # 16
square "a string" # Contract Violation...blaming Main
I’ll look at ways to automate this more in future updates.
I’ve been meaning to get around to running some performance benchmarks on contracts.coffee, but I recently learned a valuable lesson: let the internet do your work for you! :-)
I woke up this morning to find @paulmillr had put together a nice performance benchmark of contracts.coffee.
Check it out for all the gory details but suffice it to say contracts makes things…slow. This is about what I’d expected since in addition to running the actual contract check we must wrap the contracted functions/objects in a Proxy which runs handlers for each function call or property set/get. Lots of stuff is in the way of the running code.
So does the slow performance of contracts make them unusable? Not necessarily. First off, the contracts.coffee compiler can emit JavaScript with contracts completely disabled. So, you can have a “slow” testing/development build with contracts enabled to help track down bugs and a production build with contracts disabled and no slowdown.
In addition, most code is IO bound not CPU bound. So if you want contracts enabled everywhere but still care about performance, be smart about where you apply them. Put them on module boundaries, but don’t put them on tight loops for example.
In sum, contracts are another tool in the software engineer’s toolbox that have advantages (bug squashing) and disadvantages (performance slowdowns when enabled). Use them wisely.
Contracts.coffee now works in node.js! V8 (the JavaScript engine used by node) has recently added support for Proxies which contracts.coffee requires.
You’ll need a bleeding-edge version of node to get it running. Try either master (unstable) or 0.5.7. Build instructions are here.
Proxies are hidden behind a command line flag in V8 so you’ll also need to supply --harmony_proxies to node when calling the compiler:
node --harmony_proxies bin/coffee -CL test.coffee
There are almost certainly node-specific bugs in contracts.coffee so don’t trust it with anything important yet. You can get started playing though!
Report any bugs you run into on the issue tracker.