assumption-weak-hash.rkt (4902B)
1 #lang racket 2 3 ;; We use a weak hash to associate a pvar xᵢ with its the values contained in 4 ;; the derived yᵢ. The assumptions below must hold, otherwise we would risk 5 ;; memory leaks. 6 7 (require (for-syntax racket/private/sc) 8 rackunit 9 version-case) 10 11 (define h (make-weak-hasheq)) 12 13 (define (all-eq? l) 14 (foldl (λ (x acc) 15 (and (eq? x acc) acc)) 16 (car l) 17 (cdr l))) 18 19 ;; The data stored in the valvar is unique fore each use of (datum->syntax …) 20 (check-false 21 (check-duplicates 22 (for/list ([range-a (in-range 5)]) 23 (with-syntax ([(xᵢ ...) (datum->syntax #'here '(1 2 3))]) 24 (define-syntax (hh stx) 25 #`(hash-ref! h 26 #,(syntax-mapping-valvar 27 (syntax-local-value #'xᵢ)) 28 (gensym))) 29 (all-eq? (for/list ([range-b (in-range 5)]) 30 (collect-garbage) 31 (collect-garbage) 32 (collect-garbage) 33 (hh))))))) 34 35 ;; but not if the syntax object is a constant, e.g. #'(1 2 3), in Racket < 6.7 36 ;; I'm not sure how this affects subtemplate in Racket ≥ 6.7, but I suppose it 37 ;; is not a problem, as the beahviour is the same as in the general case where 38 ;; the syntax object is not constant. 39 (check-pred (version-case 40 [(version< (version) "6.90") all-eq?] 41 [else (negate all-eq?)]) 42 (for/list ([range-a (in-range 5)]) 43 (with-syntax ([(xᵢ ...) #'(1 2 3)]) ;; CHANGED THIS LINE 44 (define-syntax (hh stx) 45 #`(hash-ref! h 46 #,(syntax-mapping-valvar 47 (syntax-local-value #'xᵢ)) 48 (gensym))) 49 (all-eq? (for/list ([range-b (in-range 5)]) 50 (collect-garbage) 51 (collect-garbage) 52 (collect-garbage) 53 (hh)))))) 54 55 ;; nor it the same syntax object is reused, in Racket < 6.7 56 ;; I'm not sure how this affects subtemplate in Racket ≥ 6.7, but I suppose it 57 ;; is not a problem, as the beahviour is the same as in the general case where 58 ;; the syntax object is not shared. 59 (define stxobj (datum->syntax #'here '(1 2 3))) ;; cached stxobj here 60 (check-pred (version-case 61 [(version< (version) "6.90") all-eq?] 62 [else (negate all-eq?)]) 63 (for/list ([range-a (in-range 5)]) 64 (with-syntax ([(xᵢ ...) stxobj]) ;; CHANGED THIS LINE 65 (define-syntax (hh stx) 66 #`(hash-ref! h 67 #,(syntax-mapping-valvar 68 (syntax-local-value #'xᵢ)) 69 (gensym))) 70 (all-eq? (for/list ([range-b (in-range 5)]) 71 (collect-garbage) 72 (collect-garbage) 73 (collect-garbage) 74 (hh)))))) 75 76 77 ;; Another example showing this behaviour: 78 ;; The contents of the valvar is eq? when using a literal syntax object like: 79 ;; #'(1 2 3) 80 ;; but not with: 81 ;; (datum->syntax #'here '(1 2 3)) 82 ;; I expected the result to always be different at each execution of the 83 ;; with-syntax, but it turns out the syntax object is kept as-is. 84 ;; 85 ;; With racket ≥ 6.7, the syntax object is different, i.e. not eq?, in every 86 ;; invocation of with-syntax. 87 (begin 88 (let () 89 (define old1 #f) 90 91 (check-true 92 (andmap identity 93 (for/list ([range-a (in-range 100)]) 94 ;; #'(1 2 3) HERE: 95 (with-syntax ([(xᵢ ...) #'(1 2 3)]) 96 (define-syntax (hh stx) 97 #`#,(syntax-mapping-valvar (syntax-local-value #'xᵢ))) 98 (if (not old1) 99 ;; Initial set! 100 (set! old1 (hh)) 101 (andmap identity (for/list ([range-b (in-range 5)]) 102 ((version-case 103 [(version< (version) "6.90") eq?] 104 [else (negate eq?)]) 105 old1 106 (hh)))))))))) 107 108 (let () 109 (define old2 #f) 110 111 (check-equal? 112 (let ([res (for/list ([range-a (in-range 100)]) 113 ;; CHANGED THIS: 114 (with-syntax ([(xᵢ ...) (datum->syntax #'here '(1 2 3))]) 115 (define-syntax (hh stx) 116 #`#,(syntax-mapping-valvar (syntax-local-value #'xᵢ))) 117 (unless old2 118 ;; Initial set! 119 (set! old2 (hh))) 120 (andmap identity (for/list ([range-b (in-range 5)]) 121 (eq? old2 hh)))))]) 122 (list (car res) (ormap identity (cdr res)))) 123 '(#t #f))))