[racket] obtaining the location of an identifier

From: William Cushing (william.cushing at gmail.com)
Date: Thu Nov 21 03:05:32 EST 2013

I tried playing with the ffi to get a variable location, as suggested on
Rosetta Code:
 http://rosettacode.org/wiki/Address_of_a_variable#Racket

It also doesn't work for what you want...

Intuitively, there must be some way to suspend GC and get a hold of a
stable pointer.  (It wouldn't be possible to call nontrivial C API's
otherwise.  But I don't know Racket's FFI.)

Replacing cpointer->int with its correct definition (the integer cast of a
pinned pointer) should make the following code work as intended.

#lang racket
(require (only-in racket [set! #%set!]))
(require ffi/unsafe)

(define-syntax-rule (ref v) (cast v _racket _gcpointer))
(define (cpointer->int v) (cast v _gcpointer _fixnum))
(define global (make-custom-hash ptr-equal? cpointer->int))
(define (dump global)  (for/list (((k v) (in-dict global))) (cons (~a
(cpointer->int k)) (~a v))))

(define-syntax-rule (set! id expr)
  (let ([val expr])
    (dict-set! global (ref (#%variable-reference id)) val)
    (#%set! id val)))

(define (test)
        (define x 0)
        (set! x 1)
        (set! x 2)
        (dump global))

> (test)
'(("198044656" . "1") ("198055120" . "2"))


-Will


On Wed, Nov 20, 2013 at 10:40 AM, <users-request at racket-lang.org> wrote:

> Send users mailing list submissions to
>         users at racket-lang.org
>
> To subscribe or unsubscribe via the World Wide Web, visit
>         http://lists.racket-lang.org/users/listinfo
> or, via email, send a message with subject or body 'help' to
>         users-request at racket-lang.org
>
> You can reach the person managing the list at
>         users-owner at racket-lang.org
>
> When replying, please edit your Subject line so it is more specific
> than "Re: Contents of users digest..."
>
> [Racket Users list:
>  http://lists.racket-lang.org/users ]
>
> Today's Topics:
>
>    1. Re: obtaining the location of an identifier (Robby Findler)
>    2. Re: obtaining the location of an identifier (Sam Tobin-Hochstadt)
>    3. Re: obtaining the location of an identifier (Emina Torlak)
>
>
> ---------- Forwarded message ----------
> From: Robby Findler <robby at eecs.northwestern.edu>
> To: Emina Torlak <emina at eecs.berkeley.edu>
> Cc: users <users at racket-lang.org>
> Date: Wed, 20 Nov 2013 12:09:49 -0600
> Subject: Re: [racket] obtaining the location of an identifier
> You may be able to avoid some of those steps by rewriting the binding
> forms into macros that rewrite the uses. And it may be possible to use
> stop-lists in a good way to avoid having to actually write too much
> boilerplate for traversing expression forms that are irrelevant to you.
>
> And depending on what your'e doing, you may even find it easier/better to
> write your own language that has its own bindings form directly (and expand
> into macros that rewrite the uses).
>
> Sorry for the terse help. Good luck!
>
> Robby
>
>
> On Wed, Nov 20, 2013 at 11:35 AM, Emina Torlak <emina at eecs.berkeley.edu>wrote:
>
>> I believe Robby's solution will work.  It's basically similar to what I
>> had in mind, but I was hoping I'd be able to avoid it :)
>>
>> The crux of the issue is the need for unique identifiers for variable
>> locations.  I also track updates to vectors and structs, for example, and
>> this is easy precisely because I can use their identities to compute the
>> "location" of the update.  So, boxing values in "raw" variables will have
>> the same effect.
>>
>> In terms of implementation, though, it'll be trickier.  As far as I can
>> tell, this approach involves whole-module analysis and transformation:
>>
>> * Expand the module completely.
>> * Find all uses of set! and collect their targets.
>> * Rewrite the def and all uses of target variables to perform auto boxing
>> and unboxing.
>>
>> If there are tricks/constructs that I should use for the above steps, I'd
>> love to hear them.   Or, of course, if there is some way to obtain variable
>> location identifiers from the runtime, that would be great to know as well.
>>
>> Emina
>>
>>
>>
>>
>>
>> On Wed, Nov 20, 2013 at 5:19 AM, Robby Findler <
>> robby at eecs.northwestern.edu> wrote:
>>
>>> I didn't try it, but you it might work to use local-expand and then find
>>> all the binding forms and then rewrite them to use boxes (or some other
>>> source of uniqueness you might have around).
>>>
>>> Robby
>>>
>>>
>>> On Wed, Nov 20, 2013 at 12:53 AM, Emina Torlak <emina at eecs.berkeley.edu>wrote:
>>>
>>>> This is how my solution currently works, but unfortunately, it's not
>>>> quite right.  Here is a small example that demonstrates why, assuming the
>>>> implementation based on free-id-table:
>>>>
>>>> (define (cell init)
>>>>   (let ([x init])
>>>>     (case-lambda
>>>>       [() x]
>>>>       [(v) (set! x v)])))
>>>>
>>>> (define foo (cell 0))
>>>> (define bar (cell 1))
>>>>
>>>> > (foo 2)
>>>> > (bar 3)
>>>> > (foo)
>>>> 2
>>>> > (bar)
>>>> 3
>>>> > (dict->list global)
>>>> '((.#<syntax:18:17 x> . 3))
>>>>
>>>> In the above scenario, I need the global map to contain two bindings:
>>>>  one for the location of 'foo.x' and the other for the location of 'bar.x.'
>>>>
>>>>
>>>> Emina
>>>>
>>>>
>>>>
>>>> On Tue, Nov 19, 2013 at 10:31 PM, Sam Tobin-Hochstadt <
>>>> samth at cs.indiana.edu> wrote:
>>>>
>>>>> I think that just identifiers and `free-id-table`s should work here.
>>>>> Here's your example:
>>>>>
>>>>> #lang racket
>>>>>
>>>>> (require syntax/id-table (only-in racket [set! #%set!]))
>>>>>
>>>>> (define global (make-free-id-table))
>>>>>
>>>>> (define-syntax-rule (location-of id) #'id)
>>>>>
>>>>> (define-syntax-rule (set! id expr)
>>>>>   (let ([v expr])
>>>>>     (dict-set! global (location-of id) v)
>>>>>     (#%set! id v)))
>>>>>
>>>>> > (define x 1)
>>>>> > (set! x 2)
>>>>> > (set! x 3)
>>>>> > (for/list ([(k v) (in-dict global)]) (list k v))
>>>>> '((.#<syntax:4:8 x> 3))
>>>>>
>>>>> Also at https://gist.github.com/samth/7558673
>>>>>
>>>>> Sam
>>>>>
>>>>> On Mon, Nov 18, 2013 at 2:43 PM, Emina Torlak <emina at eecs.berkeley.edu>
>>>>> wrote:
>>>>> > I'm using Racket to implement a language for which I need to track
>>>>> state
>>>>> > updates---in particular, variable mutation using set!.  For example,
>>>>> > consider this module definition:
>>>>> >
>>>>> > #lang racket
>>>>> >
>>>>> > (require (only-in racket [set! #%set!]))
>>>>> >
>>>>> > (define global (make-hash))
>>>>> >
>>>>> > (define-syntax-rule (location-of id)
>>>>> >   (#%variable-reference id)) ; doesn't quite do the right thing
>>>>> >
>>>>> > (define-syntax-rule (set! id expr)
>>>>> >   (let ([val expr])
>>>>> >     (hash-set! global (location-of id) val)
>>>>> >     (#%set! id val)))
>>>>> >
>>>>> > When I evaluate the following sequence of forms against the above
>>>>> > definition, I would like the global hash map to contain just one
>>>>> binding
>>>>> > that maps the location for 'x' to the value 2.  With the above
>>>>> > implementation I get two map entries, since variable-reference
>>>>> doesn't quite
>>>>> > do what I hoped it did:
>>>>> >
>>>>> >> (define x 0)
>>>>> >> (set! x 1)
>>>>> >> (set! x 2)
>>>>> >> x
>>>>> > 2
>>>>> >> global
>>>>> > '#hash((#<variable-reference> . 1) (#<variable-reference> . 2))
>>>>> >
>>>>> > Is there another construct in Racket that I could use for this
>>>>> purpose?  If
>>>>> > not, can something like this be implemented and how much work would
>>>>> it
>>>>> > entail?
>>>>> >
>>>>> > I have a purely macro-based solution that works for the most part,
>>>>> but it's
>>>>> > fragile and there are corner cases for which it is just wrong.  So,
>>>>> before
>>>>> > trying to fix that, I was wondering if there is a nicer way to solve
>>>>> it by
>>>>> > somehow getting handles for variable locations that are comparable
>>>>> using eq?
>>>>> > or equal?
>>>>> >
>>>>> > Thanks!
>>>>> >
>>>>> > Emina
>>>>> >
>>>>> >
>>>>> > ____________________
>>>>> >   Racket Users list:
>>>>> >   http://lists.racket-lang.org/users
>>>>> >
>>>>>
>>>>
>>>>
>>>> ____________________
>>>>   Racket Users list:
>>>>   http://lists.racket-lang.org/users
>>>>
>>>>
>>>
>>
>
>
> ---------- Forwarded message ----------
> From: Sam Tobin-Hochstadt <samth at cs.indiana.edu>
> To: Emina Torlak <emina at eecs.berkeley.edu>
> Cc: users <users at racket-lang.org>, Robby Findler <
> robby at eecs.northwestern.edu>
> Date: Wed, 20 Nov 2013 13:28:59 -0500
> Subject: Re: [racket] obtaining the location of an identifier
> Two things:
>
> - There's code here [1] to find all the mutated variables in a module.
> - Robby's later suggestion is great if you want to track _all_
> variables, not just ones that are targets of `set!`, since you'd
> basically change everything to a box.  Otherwise I think expand/parse
> is your only option.
>
> [1]
> https://github.com/plt/racket/blob/master/pkgs/typed-racket-pkgs/typed-racket-lib/typed-racket/utils/mutated-vars.rkt
>
> On Wed, Nov 20, 2013 at 12:35 PM, Emina Torlak <emina at eecs.berkeley.edu>
> wrote:
> > I believe Robby's solution will work.  It's basically similar to what I
> had
> > in mind, but I was hoping I'd be able to avoid it :)
> >
> > The crux of the issue is the need for unique identifiers for variable
> > locations.  I also track updates to vectors and structs, for example, and
> > this is easy precisely because I can use their identities to compute the
> > "location" of the update.  So, boxing values in "raw" variables will have
> > the same effect.
> >
> > In terms of implementation, though, it'll be trickier.  As far as I can
> > tell, this approach involves whole-module analysis and transformation:
> >
> > * Expand the module completely.
> > * Find all uses of set! and collect their targets.
> > * Rewrite the def and all uses of target variables to perform auto boxing
> > and unboxing.
> >
> > If there are tricks/constructs that I should use for the above steps, I'd
> > love to hear them.   Or, of course, if there is some way to obtain
> variable
> > location identifiers from the runtime, that would be great to know as
> well.
> >
> > Emina
> >
> >
> >
> >
> >
> > On Wed, Nov 20, 2013 at 5:19 AM, Robby Findler <
> robby at eecs.northwestern.edu>
> > wrote:
> >>
> >> I didn't try it, but you it might work to use local-expand and then find
> >> all the binding forms and then rewrite them to use boxes (or some other
> >> source of uniqueness you might have around).
> >>
> >> Robby
> >>
> >>
> >> On Wed, Nov 20, 2013 at 12:53 AM, Emina Torlak <emina at eecs.berkeley.edu
> >
> >> wrote:
> >>>
> >>> This is how my solution currently works, but unfortunately, it's not
> >>> quite right.  Here is a small example that demonstrates why, assuming
> the
> >>> implementation based on free-id-table:
> >>>
> >>> (define (cell init)
> >>>   (let ([x init])
> >>>     (case-lambda
> >>>       [() x]
> >>>       [(v) (set! x v)])))
> >>>
> >>> (define foo (cell 0))
> >>> (define bar (cell 1))
> >>>
> >>> > (foo 2)
> >>> > (bar 3)
> >>> > (foo)
> >>> 2
> >>> > (bar)
> >>> 3
> >>> > (dict->list global)
> >>> '((.#<syntax:18:17 x> . 3))
> >>>
> >>> In the above scenario, I need the global map to contain two bindings:
> >>> one for the location of 'foo.x' and the other for the location of
> 'bar.x.'
> >>>
> >>> Emina
> >>>
> >>>
> >>>
> >>> On Tue, Nov 19, 2013 at 10:31 PM, Sam Tobin-Hochstadt
> >>> <samth at cs.indiana.edu> wrote:
> >>>>
> >>>> I think that just identifiers and `free-id-table`s should work here.
> >>>> Here's your example:
> >>>>
> >>>> #lang racket
> >>>>
> >>>> (require syntax/id-table (only-in racket [set! #%set!]))
> >>>>
> >>>> (define global (make-free-id-table))
> >>>>
> >>>> (define-syntax-rule (location-of id) #'id)
> >>>>
> >>>> (define-syntax-rule (set! id expr)
> >>>>   (let ([v expr])
> >>>>     (dict-set! global (location-of id) v)
> >>>>     (#%set! id v)))
> >>>>
> >>>> > (define x 1)
> >>>> > (set! x 2)
> >>>> > (set! x 3)
> >>>> > (for/list ([(k v) (in-dict global)]) (list k v))
> >>>> '((.#<syntax:4:8 x> 3))
> >>>>
> >>>> Also at https://gist.github.com/samth/7558673
> >>>>
> >>>> Sam
> >>>>
> >>>> On Mon, Nov 18, 2013 at 2:43 PM, Emina Torlak <
> emina at eecs.berkeley.edu>
> >>>> wrote:
> >>>> > I'm using Racket to implement a language for which I need to track
> >>>> > state
> >>>> > updates---in particular, variable mutation using set!.  For example,
> >>>> > consider this module definition:
> >>>> >
> >>>> > #lang racket
> >>>> >
> >>>> > (require (only-in racket [set! #%set!]))
> >>>> >
> >>>> > (define global (make-hash))
> >>>> >
> >>>> > (define-syntax-rule (location-of id)
> >>>> >   (#%variable-reference id)) ; doesn't quite do the right thing
> >>>> >
> >>>> > (define-syntax-rule (set! id expr)
> >>>> >   (let ([val expr])
> >>>> >     (hash-set! global (location-of id) val)
> >>>> >     (#%set! id val)))
> >>>> >
> >>>> > When I evaluate the following sequence of forms against the above
> >>>> > definition, I would like the global hash map to contain just one
> >>>> > binding
> >>>> > that maps the location for 'x' to the value 2.  With the above
> >>>> > implementation I get two map entries, since variable-reference
> doesn't
> >>>> > quite
> >>>> > do what I hoped it did:
> >>>> >
> >>>> >> (define x 0)
> >>>> >> (set! x 1)
> >>>> >> (set! x 2)
> >>>> >> x
> >>>> > 2
> >>>> >> global
> >>>> > '#hash((#<variable-reference> . 1) (#<variable-reference> . 2))
> >>>> >
> >>>> > Is there another construct in Racket that I could use for this
> >>>> > purpose?  If
> >>>> > not, can something like this be implemented and how much work would
> it
> >>>> > entail?
> >>>> >
> >>>> > I have a purely macro-based solution that works for the most part,
> but
> >>>> > it's
> >>>> > fragile and there are corner cases for which it is just wrong.  So,
> >>>> > before
> >>>> > trying to fix that, I was wondering if there is a nicer way to solve
> >>>> > it by
> >>>> > somehow getting handles for variable locations that are comparable
> >>>> > using eq?
> >>>> > or equal?
> >>>> >
> >>>> > Thanks!
> >>>> >
> >>>> > Emina
> >>>> >
> >>>> >
> >>>> > ____________________
> >>>> >   Racket Users list:
> >>>> >   http://lists.racket-lang.org/users
> >>>> >
> >>>
> >>>
> >>>
> >>> ____________________
> >>>   Racket Users list:
> >>>   http://lists.racket-lang.org/users
> >>>
> >>
> >
>
>
>
> ---------- Forwarded message ----------
> From: Emina Torlak <emina at eecs.berkeley.edu>
> To: Sam Tobin-Hochstadt <samth at cs.indiana.edu>
> Cc: users <users at racket-lang.org>, Robby Findler <
> robby at eecs.northwestern.edu>
> Date: Wed, 20 Nov 2013 10:40:47 -0800
> Subject: Re: [racket] obtaining the location of an identifier
> This is perfect.  I'm assuming that mutation is rare, so I'd like to
> restrict boxing only to mutated variables (the expand/parse option).  If I
> come up with something that can be nicely generalized or reused for other
> languages, I'll be sure to post it.
>
> Thanks for all the help!
>
> Emina
>
>
> On Wed, Nov 20, 2013 at 10:28 AM, Sam Tobin-Hochstadt <
> samth at cs.indiana.edu> wrote:
>
>> Two things:
>>
>> - There's code here [1] to find all the mutated variables in a module.
>> - Robby's later suggestion is great if you want to track _all_
>> variables, not just ones that are targets of `set!`, since you'd
>> basically change everything to a box.  Otherwise I think expand/parse
>> is your only option.
>>
>> [1]
>> https://github.com/plt/racket/blob/master/pkgs/typed-racket-pkgs/typed-racket-lib/typed-racket/utils/mutated-vars.rkt
>>
>> On Wed, Nov 20, 2013 at 12:35 PM, Emina Torlak <emina at eecs.berkeley.edu>
>> wrote:
>> > I believe Robby's solution will work.  It's basically similar to what I
>> had
>> > in mind, but I was hoping I'd be able to avoid it :)
>> >
>> > The crux of the issue is the need for unique identifiers for variable
>> > locations.  I also track updates to vectors and structs, for example,
>> and
>> > this is easy precisely because I can use their identities to compute the
>> > "location" of the update.  So, boxing values in "raw" variables will
>> have
>> > the same effect.
>> >
>> > In terms of implementation, though, it'll be trickier.  As far as I can
>> > tell, this approach involves whole-module analysis and transformation:
>> >
>> > * Expand the module completely.
>> > * Find all uses of set! and collect their targets.
>> > * Rewrite the def and all uses of target variables to perform auto
>> boxing
>> > and unboxing.
>> >
>> > If there are tricks/constructs that I should use for the above steps,
>> I'd
>> > love to hear them.   Or, of course, if there is some way to obtain
>> variable
>> > location identifiers from the runtime, that would be great to know as
>> well.
>> >
>> > Emina
>> >
>> >
>> >
>> >
>> >
>> > On Wed, Nov 20, 2013 at 5:19 AM, Robby Findler <
>> robby at eecs.northwestern.edu>
>> > wrote:
>> >>
>> >> I didn't try it, but you it might work to use local-expand and then
>> find
>> >> all the binding forms and then rewrite them to use boxes (or some other
>> >> source of uniqueness you might have around).
>> >>
>> >> Robby
>> >>
>> >>
>> >> On Wed, Nov 20, 2013 at 12:53 AM, Emina Torlak <
>> emina at eecs.berkeley.edu>
>> >> wrote:
>> >>>
>> >>> This is how my solution currently works, but unfortunately, it's not
>> >>> quite right.  Here is a small example that demonstrates why, assuming
>> the
>> >>> implementation based on free-id-table:
>> >>>
>> >>> (define (cell init)
>> >>>   (let ([x init])
>> >>>     (case-lambda
>> >>>       [() x]
>> >>>       [(v) (set! x v)])))
>> >>>
>> >>> (define foo (cell 0))
>> >>> (define bar (cell 1))
>> >>>
>> >>> > (foo 2)
>> >>> > (bar 3)
>> >>> > (foo)
>> >>> 2
>> >>> > (bar)
>> >>> 3
>> >>> > (dict->list global)
>> >>> '((.#<syntax:18:17 x> . 3))
>> >>>
>> >>> In the above scenario, I need the global map to contain two bindings:
>> >>> one for the location of 'foo.x' and the other for the location of
>> 'bar.x.'
>> >>>
>> >>> Emina
>> >>>
>> >>>
>> >>>
>> >>> On Tue, Nov 19, 2013 at 10:31 PM, Sam Tobin-Hochstadt
>> >>> <samth at cs.indiana.edu> wrote:
>> >>>>
>> >>>> I think that just identifiers and `free-id-table`s should work here.
>> >>>> Here's your example:
>> >>>>
>> >>>> #lang racket
>> >>>>
>> >>>> (require syntax/id-table (only-in racket [set! #%set!]))
>> >>>>
>> >>>> (define global (make-free-id-table))
>> >>>>
>> >>>> (define-syntax-rule (location-of id) #'id)
>> >>>>
>> >>>> (define-syntax-rule (set! id expr)
>> >>>>   (let ([v expr])
>> >>>>     (dict-set! global (location-of id) v)
>> >>>>     (#%set! id v)))
>> >>>>
>> >>>> > (define x 1)
>> >>>> > (set! x 2)
>> >>>> > (set! x 3)
>> >>>> > (for/list ([(k v) (in-dict global)]) (list k v))
>> >>>> '((.#<syntax:4:8 x> 3))
>> >>>>
>> >>>> Also at https://gist.github.com/samth/7558673
>> >>>>
>> >>>> Sam
>> >>>>
>> >>>> On Mon, Nov 18, 2013 at 2:43 PM, Emina Torlak <
>> emina at eecs.berkeley.edu>
>> >>>> wrote:
>> >>>> > I'm using Racket to implement a language for which I need to track
>> >>>> > state
>> >>>> > updates---in particular, variable mutation using set!.  For
>> example,
>> >>>> > consider this module definition:
>> >>>> >
>> >>>> > #lang racket
>> >>>> >
>> >>>> > (require (only-in racket [set! #%set!]))
>> >>>> >
>> >>>> > (define global (make-hash))
>> >>>> >
>> >>>> > (define-syntax-rule (location-of id)
>> >>>> >   (#%variable-reference id)) ; doesn't quite do the right thing
>> >>>> >
>> >>>> > (define-syntax-rule (set! id expr)
>> >>>> >   (let ([val expr])
>> >>>> >     (hash-set! global (location-of id) val)
>> >>>> >     (#%set! id val)))
>> >>>> >
>> >>>> > When I evaluate the following sequence of forms against the above
>> >>>> > definition, I would like the global hash map to contain just one
>> >>>> > binding
>> >>>> > that maps the location for 'x' to the value 2.  With the above
>> >>>> > implementation I get two map entries, since variable-reference
>> doesn't
>> >>>> > quite
>> >>>> > do what I hoped it did:
>> >>>> >
>> >>>> >> (define x 0)
>> >>>> >> (set! x 1)
>> >>>> >> (set! x 2)
>> >>>> >> x
>> >>>> > 2
>> >>>> >> global
>> >>>> > '#hash((#<variable-reference> . 1) (#<variable-reference> . 2))
>> >>>> >
>> >>>> > Is there another construct in Racket that I could use for this
>> >>>> > purpose?  If
>> >>>> > not, can something like this be implemented and how much work
>> would it
>> >>>> > entail?
>> >>>> >
>> >>>> > I have a purely macro-based solution that works for the most part,
>> but
>> >>>> > it's
>> >>>> > fragile and there are corner cases for which it is just wrong.  So,
>> >>>> > before
>> >>>> > trying to fix that, I was wondering if there is a nicer way to
>> solve
>> >>>> > it by
>> >>>> > somehow getting handles for variable locations that are comparable
>> >>>> > using eq?
>> >>>> > or equal?
>> >>>> >
>> >>>> > Thanks!
>> >>>> >
>> >>>> > Emina
>> >>>> >
>> >>>> >
>> >>>> > ____________________
>> >>>> >   Racket Users list:
>> >>>> >   http://lists.racket-lang.org/users
>> >>>> >
>> >>>
>> >>>
>> >>>
>> >>> ____________________
>> >>>   Racket Users list:
>> >>>   http://lists.racket-lang.org/users
>> >>>
>> >>
>> >
>>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20131121/2e127f9c/attachment-0001.html>

Posted on the users mailing list.