[racket-dev] Generics scoping issues

From: J. Ian Johnson (ianj at ccs.neu.edu)
Date: Fri Aug 16 17:39:29 EDT 2013

WRT the struct abstraction, using syntax-local-introduce on #'gen:binds-variables seemed to do the trick, oddly.
-Ian
----- Original Message -----
From: "Carl Eastlund" <cce at ccs.neu.edu>
To: "J. Ian Johnson" <ianj at ccs.neu.edu>
Cc: "dev" <dev at racket-lang.org>
Sent: Friday, August 16, 2013 5:23:33 PM GMT -05:00 US/Canada Eastern
Subject: Re: [racket-dev] Generics scoping issues


Okay, let me dig into this. The expansion of define/generic is an odd thing in the way it treats the method names; I'm not at all sure I've gotten it right, or that it's clear what "right" should even be. I'll get back to you shortly. 



Carl Eastlund 


On Fri, Aug 16, 2013 at 5:17 PM, J. Ian Johnson < ianj at ccs.neu.edu > wrote: 


Re: problem 1 - ah yes I see. 
Problem 2: 
In the body of def-free: 

generic-problems.rkt:16:26: define/generic: free is not a method of generic interfaces gen:binds-variables 
at: free 
in: (define/generic gfree free) 

This compiles if I additionally supply def-free with free, but it doesn't run: 
free-box: undefined; 
cannot reference an identifier before its definition 
in module: "/home/ianj/projects/oaam/code/generic-problems.rkt" 
context...: 
/home/ianj/projects/oaam/code/generic-problems.rkt: [running body] 

Furthermore, if I abstract over the struct form so that #:methods gen:binds-variables is part of the macro expansion, even passing free to def-free won't work anymore: 

(define-syntax-rule (astruct name (fields ...) (methods ...)) 
(struct name exp (fields ...) #:transparent #:methods gen:binds-variables [methods ...])) 

(astruct avar (name) 
[(def-free e gfree free bound avar [(x) (if (x . ∈ . bound) ∅ (set x))])]) 

generic-problems.rkt:31:27: define/generic: free is not a method of generic interfaces gen:binds-variables 
at: free 
in: (define/generic gfree free) 




----- Original Message ----- 
From: "Carl Eastlund" < cce at ccs.neu.edu > 
To: "J. Ian Johnson" < ianj at ccs.neu.edu > 
Cc: "dev" < dev at racket-lang.org > 
Sent: Friday, August 16, 2013 4:50:53 PM GMT -05:00 US/Canada Eastern 
Subject: Re: [racket-dev] Generics scoping issues 



Problem 1 -- you have to use define/generic if you want to use the generic version of something in the context of a set of specific method implementations. That's by design. 

Problem 2 -- what error message or unexpected behavior are you getting? That should work, it sounds like a bug in define/generic if it's not working. 



Carl Eastlund 


On Fri, Aug 16, 2013 at 4:36 PM, J. Ian Johnson < ianj at ccs.neu.edu > wrote: 


I'm starting to use generics, and me being myself, I wrote some macros to make writing method definitions easier. 
But, I'm seeing that #:methods seems to rebind method identifiers in a way that hygiene interferes with. 

I would expect to be allowed to do the following two things (problems annotated): 

(struct exp (label fvs-box)) ;; parent struct for all expressions 
(define-generics binds-variables 
[free-box binds-variables] 
[free binds-variables #:bound [bound]] 
#:fallbacks [(define (free e #:bound [bound ∅]) ∅) 
(define free-box exp-fvs-box)] 
#:fast-defaults ([(compose unbox free-box) 
(define (free e #:bound bound) (unbox (free-box e)))])) ;; problem 1: free-box not in scope 

(define-syntax-rule (def-free e gfree bound struct [(pats ...) rhss ...]) 
(begin 
(define/generic gfree free) ;; problem 2: since #:methods rebinds free, this is not in the scope one would expect with its definition in the define-generics form. 
(define (free e #:bound [bound ∅]) 
(match e [(struct _ fvs-box pats ...) 
(set-box! fvs-box 
(let () rhss ...))])))) 

(struct var exp (name) #:transparent 
#:methods gen:binds-variables 
[(def-free e gfree bound var [(x) (if (x . ∈ . bound) ∅ (set x))])]) 

I have workarounds thanks to stamourv, but they're unpleasant: 
Problem 1: define free in fast-defaults as an eta-expansion of a definition outside the define-generics form that does what you want. 
Problem 2: add free as a parameter to def-free, and pass free in at all uses of def-free. 

The first problem seems like more of a programming error than the use of the wrong tool. 
The second problem seems like generic method identifiers should be syntax-parameters, if they indeed need to be rebound in the rhs of the #:methods argument. 

Are these expectations unreasonable/against the design decisions for generics? 
Thanks, 
-Ian 

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





Posted on the dev mailing list.