[racket-dev] Generics scoping issues

From: Carl Eastlund (cce at ccs.neu.edu)
Date: Fri Aug 16 18:51:59 EDT 2013

The method name you give to define/generic is interpreted in the context of
the generic interface name you provide.  So if you supply the name "free"
inside a macro, that's the wrong context.  That error goes away, as you
found, if you pass "free" as an argument to def-free.

After that, you get the error "free-box: undefined" because the
#:fast-defaults predicate is lifted to a definition that comes before the
definition of the free-box method.  I'll fix that by reordering the
definitions; meanwhile you can fix that by just eta-expanding your use of
"compose".

Carl Eastlund


On Fri, Aug 16, 2013 at 5:41 PM, Carl Eastlund <cce at ccs.neu.edu> wrote:

> The method names are always going to be in the context of the generic
> interface name.  There's nowhere else they can come from.
>
> Carl Eastlund
>
>
> On Fri, Aug 16, 2013 at 5:39 PM, J. Ian Johnson <ianj at ccs.neu.edu> wrote:
>
>> 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
>>
>>
>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/dev/archive/attachments/20130816/7ef19ca1/attachment.html>

Posted on the dev mailing list.