[racket-dev] Generics scoping issues

From: J. Ian Johnson (ianj at ccs.neu.edu)
Date: Sat Aug 17 08:49:21 EDT 2013

I discovered that afterwards, yes. However I do want to short-circuit just calls to free to use the defaults, not free-box. Currently I have to check the box in each instance.
-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: Fri, 16 Aug 2013 19:48:58 -0400 (EDT)
Subject: Re: [racket-dev] Generics scoping issues

Mind you, I don't think this example -- using a method in a #:fast-defaults
predicate -- can work.  The implementation of free-box will have to check
the predicate in order to perform generic dispatch, and the predicate has
to call free-box, so it will diverge.

Carl Eastlund


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

> 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
>>>
>>>
>>>
>>>
>>>
>>
>



Posted on the dev mailing list.