<div dir="ltr">Hi all, <div><br></div><div><br></div><div>In case this might interest some folks here. I now work for a start up in New York. We're doing physics-based analysis of green buildings. I just received permission to release our JavaScript implementation of Racket's contracts under an open source license, MPL to be precise.</div>
<div><br></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div style><a href="https://github.com/sefaira/rho-contracts.js">https://github.com/sefaira/rho-contracts.js</a></div></blockquote><div><br></div>
<div style>After some fiddling, I was able to create a syntax that's readable enough (I hope). Here is the `derive` function wrapped in a contract:<br><br></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px">
<div style><font face="courier new, monospace">var c = require('contract')</font></div><div style><font face="courier new, monospace"><br></font></div><div style><font face="courier new, monospace" color="#990000">// define the contract that's used below (since it's used twice):</font></div>
<div style><font face="courier new, monospace">c.numberToNumber = c.fun( { x: c.number } ).returns(c.number)</font></div><div style><font face="courier new, monospace"><br></font></div><div style><font face="courier new, monospace" color="#990000">// derive: returns a function that is the numerically-computed derivative</font></div>
<div style><font face="courier new, monospace" color="#990000">// of the given function.</font></div><div style><font face="courier new, monospace">var derive =</font></div><div style><font face="courier new, monospace" color="#38761d"> </font><font face="courier new, monospace" color="#990000">/* This is the specification: */ </font></div>
<div style><font face="courier new, monospace"> c.fun( { fn: c.numberToNumber },</font></div><div style><font face="courier new, monospace"> { deltaX: c.number } )</font></div><div style><font face="courier new, monospace"> .returns(c.numberToNumber)</font></div>
<div style><font face="courier new, monospace"> .wrap(</font></div><div style><font face="courier new, monospace"> <font color="#990000">/* And the implementation goes here: */ </font></font></div><div style><font face="courier new, monospace"> function(fn, deltaX) { </font></div>
<div style><font face="courier new, monospace"> return function(x) { </font></div><div style><font face="courier new, monospace"> return (fn(x+deltaX/2) - fn(x-deltaX/2))/deltaX</font></div><div style>
<font face="courier new, monospace"> }</font></div><div style><font face="courier new, monospace"> })</font></div></blockquote><div style><br>Once the contract is in place, you get the kind of error message you always wanted to have in JavaScript, but never could, such as the basic "wrong number of arguments.", and you also get contract error with blame (though only function-level blame, not between-module blame):</div>
<div><br><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div style><div style><div style><font face="courier new, monospace"> </font><span style="color:rgb(153,0,0);font-family:'courier new',monospace">// Error: forgetting an argument:</span></div>
<div><font face="courier new, monospace"><font color="#990000"> </font>> derive(quadratic)</font></div><div><font face="courier new, monospace"> <font color="#ff0000">ContractError: Wrong number of arguments, expected 2 but got 1</font></font></div>
<div><font face="courier new, monospace"><br></font></div><div style><font face="courier new, monospace"> </font><span style="color:rgb(153,0,0);font-family:'courier new',monospace">// Error: calling with the arguments flipped:</span></div>
<div><font face="courier new, monospace"><font color="#990000"> </font>> derive(1.0, quadratic)</font></div><div><font face="courier new, monospace"> <font color="#ff0000">ContractError: Expected fun, but got 1</font></font></div>
<div><font face="courier new, monospace" color="#ff0000"> For the `fn` argument of the call.</font></div><div><font face="courier new, monospace"><br></font></div><div style><span style="font-family:'courier new',monospace"> </span><span style="font-family:'courier new',monospace"> </span><font face="courier new, monospace"><font color="#990000">// Error: calling with the wrong kind of function:</font></font></div>
</div></div><div style><div style><font face="courier new, monospace"><font color="#990000"> </font>> var d = derive(function(x) { return "**" + x + "**" }, 1.0)</font></div></div><div style><div style>
<font face="courier new, monospace"><br></font></div></div><div style><div style><font face="courier new, monospace"> <font color="#990000">// The contract-checking shell is now installed around `fn` inside of `d`;</font></font></div>
</div><div style><div style><font face="courier new, monospace" color="#990000"> // throws an error when called:</font></div></div><div style><div style><font face="courier new, monospace"><font color="#990000"> </font>> d(100)</font></div>
</div><div style><div style><font face="courier new, monospace"> <font color="#ff0000">ContractError: `fn()` broke its contract</font></font></div></div><div style><div style><font face="courier new, monospace" color="#ff0000"> Expected number, but got '**100.5**'</font></div>
</div><div style><div style><font face="courier new, monospace" color="#ff0000"> for the return value of the call.</font></div></div></blockquote><font color="#ff0000" face="courier new, monospace"><br></font></div><div>
<br></div>There is also support for placing contract on whole module at a time. Notably, the contract library itself is wrapped with contracts, as it should:<div><br></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px">
<div style><a href="https://github.com/sefaira/rho-contracts.js/blob/master/contract.face.js">https://github.com/sefaira/rho-contracts.js/blob/master/contract.face.js</a></div></blockquote><div><br></div><div style>This has been in production at <a href="http://sefaira.com">sefaira.com</a> for about a year now. We're really happy to have a piece of Racket-lore be our first open source release. Hopefully there will be more.</div>
<div style><br></div><div style><br></div><div style>Best,</div><div style><br></div><div style>Guillaume</div><div><br></div><div><br></div><div><br><div><br></div><div><br></div></div></div>