is sound gradual typing dead
play

Is Sound Gradual Typing Dead? Asumu Takikawa Daniel Feltey Ben - PowerPoint PPT Presentation

Is Sound Gradual Typing Dead? Asumu Takikawa Daniel Feltey Ben Greenman Max S. New Jan Vitek Matthias Felleisen Gradual typing thesis 1. People write untyped code 2. Static types help maintain software 3. Sound types can be added


  1. Is Sound Gradual Typing Dead? Asumu Takikawa Daniel Feltey Ben Greenman Max S. New Jan Vitek Matthias Felleisen

  2. Gradual typing thesis 1. People write untyped code 2. Static types help maintain software 3. Sound types can be added incrementally 4. Types respect existing code & the result is runnable

  3. Sound types

  4. Unsound Typed Untyped The meaning of soundness #lang typed/racket/unsound #lang racket ; fact.rkt ; use.rkt (provide fact) (require "fact.rkt") (: fact (-> Integer Integer)) (fact "ill-typed call") (define (fact n) (if (zero? n) 1 (* n (sub1 n))))

  5. Unsound Typed Untyped The meaning of soundness #lang typed/racket/unsound #lang racket ; fact.rkt ; use.rkt (provide fact) (require "fact.rkt") ; zero?: contract violation ; expected: number? (: fact (-> Integer Integer)) (fact "ill-typed call") ; given: "ill-typed call" (define (fact n) ; [,bt for context] (if (zero? n) 1 (* n (sub1 n))))

  6. Unsound Typed Untyped The meaning of soundness #lang typed/racket #lang racket ; fact.rkt ; use.rkt (provide fact) (require "fact.rkt") (: fact (-> Integer Integer)) (fact "ill-typed call") (define (fact n) (if (zero? n) 1 (* n (sub1 n))))

  7. Unsound Typed Untyped The meaning of soundness #lang typed/racket #lang racket ; fact.rkt ; use.rkt ; fact: contract violation ; expected: Integer (provide fact) (require "fact.rkt") ; given: "ill-typed call" ; in: the 1st argument of (: fact (-> Integer Integer)) (fact "ill-typed call") ; (-> Integer any) (define (fact n) ; contract from: "fact.rkt" (if (zero? n) ; blaming: "use.rkt" 1 (* n (sub1 n))))

  8. Results are runnable

  9. Prime number sieve #lang racket/base #lang racket/base (provide (struct-out stream) (require "streams.rkt") make-stream stream-unfold stream-get stream-take) (define (count-from n) (struct stream (first rest)) (make-stream n (lambda () (count-from (add1 n))))) (define (make-stream hd thunk) (stream hd thunk)) (define (sift n st) (define-values (hd tl) (stream-unfold st)) (define (stream-unfold st) (cond [(= 0 (modulo hd n)) (sift n tl)] (values (stream-first st) [else ((stream-rest st)))) (make-stream hd (lambda () (sift n tl)))])) (define (stream-get st i) (define-values (hd tl) (define (sieve st) (stream-unfold st)) (define-values (hd tl) (cond [(= i 0) hd] (stream-unfold st)) [else (stream-get tl (sub1 i))])) (make-stream hd (lambda () (sieve (sift hd tl))))) (define (stream-take st n) (define primes (sieve (count-from 2))) (cond [(= n 0) '()] [else (define (main) (define-values (hd tl) (stream-unfold st)) (printf "The ~a-th prime number is: ~a\n" 100 (cons hd (stream-take tl (sub1 n)))])) (stream-get primes 99))) (time (main))

  10. Prime number sieve #lang racket/base #lang racket/base (provide (struct-out stream) (require "streams.rkt") make-stream stream-unfold stream-get stream-take) (define (count-from n) (struct stream (first rest)) (make-stream n (lambda () (count-from (add1 n))))) (define (make-stream hd thunk) (stream hd thunk)) (define (sift n st) (define-values (hd tl) (stream-unfold st)) (define (stream-unfold st) (cond [(= 0 (modulo hd n)) (sift n tl)] (values (stream-first st) [else ((stream-rest st)))) (make-stream hd (lambda () (sift n tl)))])) (define (stream-get st i) (define-values (hd tl) (define (sieve st) (stream-unfold st)) (define-values (hd tl) (cond [(= i 0) hd] (stream-unfold st)) [else (stream-get tl (sub1 i))])) (make-stream hd (lambda () (sieve (sift hd tl))))) (define (stream-take st n) (define primes (sieve (count-from 2))) (cond [(= n 0) '()] [else (define (main) (define-values (hd tl) (stream-unfold st)) (printf "The ~a-th prime number is: ~a\n" 100 (cons hd (stream-take tl (sub1 n)))])) (stream-get primes 99))) (time (main))

  11. A Typed Racket demo - prime number sieve Prime number sieve #lang typed/racket/base #lang racket/base (provide (struct-out stream) (require "streams.rkt") make-stream stream-unfold stream-get stream-take) (define (count-from n) (struct: stream ([first : Natural] (make-stream [rest : (-> stream)])) n (lambda () (count-from (add1 n))))) (: make-stream (-> Natural (-> stream) stream)) (define (sift n st) (define (make-stream hd thunk) (define-values (hd tl) (stream-unfold st)) (stream hd thunk)) (cond [(= 0 (modulo hd n)) (sift n tl)] [else (: stream-unfold (-> stream (values Natural stream))) (make-stream (define (stream-unfold st) hd (lambda () (sift n tl)))])) (values (stream-first st) ((stream-rest st)))) (define (sieve st) (define-values (hd tl) (: stream-get (-> stream Natural Natural)) (stream-unfold st)) (define (stream-get st i) (make-stream hd (lambda () (sieve (sift hd tl))))) (define-values (hd tl) (stream-unfold st)) (define primes (sieve (count-from 2))) (cond [(= i 0) hd] [else (stream-get tl (sub1 i))])) (define (main) (printf "The ~a-th prime number is: ~a\n" 100 (: stream-take (-> stream Natural (Listof Natural))) (stream-get primes 99))) (define (stream-take st n) (cond [(= n 0) '()] (time (main)) [else (define-values (hd tl) (stream-unfold st)) (cons hd (stream-take tl (sub1 n)))]))

  12. A Typed Racket demo - prime number sieve Prime number sieve #lang typed/racket/base #lang racket/base (provide (struct-out stream) (require "streams.rkt") make-stream stream-unfold stream-get stream-take) (define (count-from n) (struct: stream ([first : Natural] (make-stream [rest : (-> stream)])) n (lambda () (count-from (add1 n))))) (: make-stream (-> Natural (-> stream) stream)) (define (sift n st) (define (make-stream hd thunk) (define-values (hd tl) (stream-unfold st)) (stream hd thunk)) (cond [(= 0 (modulo hd n)) (sift n tl)] [else (: stream-unfold (-> stream (values Natural stream))) (make-stream (define (stream-unfold st) hd (lambda () (sift n tl)))])) (values (stream-first st) ((stream-rest st)))) (define (sieve st) (define-values (hd tl) (: stream-get (-> stream Natural Natural)) (stream-unfold st)) (define (stream-get st i) (make-stream hd (lambda () (sieve (sift hd tl))))) (define-values (hd tl) (stream-unfold st)) (define primes (sieve (count-from 2))) (cond [(= i 0) hd] [else (stream-get tl (sub1 i))])) (define (main) (printf "The ~a-th prime number is: ~a\n" 100 (: stream-take (-> stream Natural (Listof Natural))) (stream-get primes 99))) (define (stream-take st n) (cond [(= n 0) '()] (time (main)) [else (define-values (hd tl) (stream-unfold st)) (cons hd (stream-take tl (sub1 n)))]))

  13. 10x slowdown could make the software undeliverable

  14. Anecdotes from users “The end-product appears to be a 50%-performance 2x hybrid due to boundary contracts” “At this point, about one- fi fth of my code is now typed. 2.5x Unfortunately, this version is 2.5 times slower” “On my machine, it takes *twelve seconds* ... 12,000x ... the time taken is 1ms”

  15. “As a practitioner, there are costs associated with using TR, therefore it has to provide equivalent performance improvements to be worthwhile at all.” — Matthew Butterick

  16. Why is it slow? Bad programming / isolated incidents? Bad implementation / design? Fundamental issue with gradual typing?

  17. To answer, we need an evaluation method

  18. Contributions of our paper ‣ Evaluation method for language implementors ‣ Idea for graphically summarizing evaluation results ‣ Results of evaluating Typed Racket using the method

  19. Key Concepts

  20. Programmers add types incrementally so should the evaluation method

  21. Suf fi xtree benchmark with 6 modules

  22. Reminder: incremental addition of types

  23. The performance lattice Paths in lattice are gradual migration paths

  24. Why are the con fi gs useful? Reveals the cost of boundaries in gradual programs Shows paths from untyped to typed

  25. data label lcs main structs ukkonen 231570 ms / 88.72x data label lcs main structs ukkonen 195755 ms / 75x Data / Label boundary is costly

  26. data label lcs main structs ukkonen 33294 ms / 12.76x data label lcs main structs ukkonen 22203 ms / 8.51x When Data / Label have same color, it's more ok

  27. The visualization has some limitations

  28. Which one is better? a b c d a b c d 8x 0.08x a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d 1.25x 10.38x 1.25x 7x 0.71x 0.54x 1.26x 1.12x a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d 2.63x 5.13x 5.38x 2.75x 8.38x 11.88x 1.24x 0.85x 0.59x 0.31x 0.14x 1.1x a b c d a b c d a b c d a b c d a b c d a b c d a b c d a b c d 2.88x 11.5x 5.88x 2.25x 0.19x 1.04x 0.87x 0.95x a b c d a b c d 1x 1x Version 1 Version 2

Recommend


More recommend