1. Robby responded to your first item some time back. He and I had discussed 
contract-stronger and eq? check several times in the past. But even that 
doesn't assure improved checking w/o some performance-oriented thinking on the 
programmer's side. 

2. Sam didn't respond to the second part, which contained two questions. To 
answer the first one, I changed your code a bit. As for the second one, I think 
it is a lack os smarts but I am not sure this smarts can be exploited. See 
below, with modifications labeled MF. 

3. Because we anticipated performance distortions by contracts, Robby and I 
decided to make contracts a 'module' level tool. The hope was that Racket 
programmers would (1) trust themselves with their own code within a module ("No 
panic on the Titanic" was my slogan to remind ourselves of this argument; why 
choose an untyped language otherwise?) and (2) avoid 'tight' loops across 
module boundaries. 

Note: Since then we have learned that Racket programmers don't trust 
themselves; see the introduction of define/contract and friends and the 
repeated misunderstanding that this would check contracts even for internal 
recursive calls. We have also learned that in the context of generated 
contracts -- TR -- tight loops might show up. 

I am beginning to wonder whether the work on Optimization Coach should turn to 
this area next i.e. whether we should figure out a tool that anticipates 
potential performance problems in linked programs. As a stand-alone library 
racket/math clearly doesn't pose any problems. When linked into an untyped 
context, things might go wrong however -- as your toy benchmark shows. Or we 
just sit back and hope that nobody is ever bothered by this performance hit 
because 'realistic' programs won't suffer from this problem. 

-- Matthias



#lang racket

;; Provides a predicate and constructor for the opaque type `Foo'
(module foo-defs racket
 (provide foo? make-foo set-foos foos)

 (define (make-foo x) x)

 (define (foo? x)
   (printf "foo?~n")
   (exact-integer? x))
  
  ;; MF: manipulate foos behind your back 
  (define (set-foos v)
    (vector-set! v 5 (exact->inexact (vector-ref v 5))))
  
  ;; MF: make foos here 
  (define foos (build-vector 10 make-foo)))

(module typed-defs typed/racket
 (provide get-foo foo-ap bar-ap)

 (require/typed
  (submod ".." foo-defs)
  [#:opaque Foo foo?]
  [make-foo (Integer -> Foo)]
  ;; MF: type foos properly 
  [foos (Vectorof Foo)] 
  ;; MF: promise the world here 
  [set-foos ((Vectorof Foo) -> Void)])

 ;; prints `foo?' 10 times; definitely necessary
 
 (: get-foo (Integer -> Foo))
 (define (get-foo i)
   (vector-ref foos i))

 (: foo-ap (All (A) ((Foo -> A) Foo -> A)))
 (define (foo-ap f foo)
   (f foo))
  
  (: bar-ap (All (A) ((Foo -> A) Integer -> A)))
 (define (bar-ap f foo)
   (f (get-foo foo))))

(require 'typed-defs 'foo-defs)

; I don't understand why the contract for `get-foo' has to check the return 
value, because TR already ensures that `get-foo' always returns a `Foo':

(printf "going to get a foo~n")
(set-foos foos) ;; MF: this does NOT raise an error
(with-handlers ((exn:fail:contract:blame? void))
  (get-foo 5) ; prints `foo?' once; why? MF: because it could have been 
modified, despite the type 
  (displayln "ouch, it didn't catch the problem"))

; Could TR generate (exact-integer? . -> . any) for `get-foo'?

; Relatedly, TR already ensures that the function passed to `foo-ap' is only 
applied to `Foo' values, but this is also checked by a contract:

(printf "going to apply a function to a foo~n")
(with-handlers ((exn:fail:contract:blame? void))
  (foo-ap identity (exact->inexact (get-foo 1))))  ; prints `foo?' twice; why 
not once, just for 1?
;; MF: the first time because it might get a bad foo


(bar-ap identity 5)  ; prints `foo?' twice; why not once, just for 1?
;; MF: After some playing around, I don't know either. 
;; Conjecture: the translation of the All type does not take into account that 
no matter what (Foo -> A) is applied to a Foo 
;; -- statically typed for sure, and possibly protected with a contract 


_________________________
  Racket Developers list:
  http://lists.racket-lang.org/dev

Reply via email to