[racket] disabling contracts again

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Fri May 18 19:05:59 EDT 2012

On May 18, 2012, at 6:24 PM, Neil Van Dyke wrote:

> Any new thoughts on adding a feature for disabling contracts?
> In the past, I have been concerned about introducing contracts into large performance-sensitive apps, since I didn't know the performance impact.  I couldn't measure the performance impact without a large amount of work that might have to then be thrown away.  The solution was to simply not try using contracts.
> I am newly interested in disabling contracts because my new code documentation tool encourages the use of contracts, as well as developing your modules as PLaneT packages.  However, as I am converting all my PLaneT packages to use contracts, I fear this will make the packages less useful to people who don't want the contract overhead.
> Or, if no one is persuaded that this might be a good thing, perhaps there's a submodules angle that makes implementing disable-able contracts interesting to someone?  If so, it might also be relevant to Typed Racket.

When it comes to the cost of contracts you need to distinguish two different costs: 

 1. the cost of writing (provide/contract [f any/c]). This cost tends to be very very very low.  

 2. the cost of executing the programmer's contract. This cost is entirely controlled by the programmer. 

I know that point 2 doesn't say anything generally applicable. But that's all we can say. You can test very shallow properties at a module boundary. You can check complete correctness for flat properties. You can partially check higher-order properties for all uses in a program or you can sample them randomly (we're working on this one right now) once and for all. In the end it is you who chooses how much to check and how much your software component must be protected and how much it must promise to others on your team. 

;; ---- 

As for measuring and/or disabling contracts, you can always export all functionality twice, via submodules now. See code below. I am sure one could create macros that abstract over what you want imported. 

#lang racket ;; client.rkt

; (require (submod "server.rkt" export/c))
;; > (test 3)
;; cpu time: 552 real time: 558 gc time: 28
;; cpu time: 534 real time: 538 gc time: 27
;; cpu time: 533 real time: 537 gc time: 27
;; cpu time: 536 real time: 538 gc time: 26
;; cpu time: 543 real time: 548 gc time: 26

(require (submod "server.rkt" export))
;; > (test 3)
;; cpu time: 243 real time: 243 gc time: 0
;; cpu time: 230 real time: 230 gc time: 0
;; cpu time: 238 real time: 239 gc time: 0
;; cpu time: 233 real time: 234 gc time: 0
;; cpu time: 231 real time: 232 gc time: 0

(define (test N)
  (collect-garbage) (collect-garbage) (collect-garbage)
  (define l (build-list 10000 add1))
  (define s 
      (lambda ()
        (for ((i N))
          (show sqr l))))))
  (string-length s))

#lang racket ;; server.rkt 

(module+ export
         (provide show))

(module+ export/c
          [show (->i ([f (->i ((x integer?)) (y (x) (and/c integer? (>=/c x))))] [l list?]) [result (l) (and/c integer? (>=/c (apply + l)))])]))

(define (show f l)
  (for/fold ([sum 0]) ((x l))
    (define term (f x))
    (displayln `(,x ,term))
    (+ sum term)))

Posted on the users mailing list.