<div dir="ltr">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.<div>
<br></div><div>Thanks for all the help!  <br></div><div><br></div><div>Emina</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Wed, Nov 20, 2013 at 10:28 AM, Sam Tobin-Hochstadt <span dir="ltr"><<a href="mailto:samth@cs.indiana.edu" target="_blank">samth@cs.indiana.edu</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Two things:<br>
<br>
- There's code here [1] to find all the mutated variables in a module.<br>
- Robby's later suggestion is great if you want to track _all_<br>
variables, not just ones that are targets of `set!`, since you'd<br>
basically change everything to a box.  Otherwise I think expand/parse<br>
is your only option.<br>
<br>
[1] <a href="https://github.com/plt/racket/blob/master/pkgs/typed-racket-pkgs/typed-racket-lib/typed-racket/utils/mutated-vars.rkt" target="_blank">https://github.com/plt/racket/blob/master/pkgs/typed-racket-pkgs/typed-racket-lib/typed-racket/utils/mutated-vars.rkt</a><br>

<div class="HOEnZb"><div class="h5"><br>
On Wed, Nov 20, 2013 at 12:35 PM, Emina Torlak <<a href="mailto:emina@eecs.berkeley.edu">emina@eecs.berkeley.edu</a>> wrote:<br>
> I believe Robby's solution will work.  It's basically similar to what I had<br>
> in mind, but I was hoping I'd be able to avoid it :)<br>
><br>
> The crux of the issue is the need for unique identifiers for variable<br>
> locations.  I also track updates to vectors and structs, for example, and<br>
> this is easy precisely because I can use their identities to compute the<br>
> "location" of the update.  So, boxing values in "raw" variables will have<br>
> the same effect.<br>
><br>
> In terms of implementation, though, it'll be trickier.  As far as I can<br>
> tell, this approach involves whole-module analysis and transformation:<br>
><br>
> * Expand the module completely.<br>
> * Find all uses of set! and collect their targets.<br>
> * Rewrite the def and all uses of target variables to perform auto boxing<br>
> and unboxing.<br>
><br>
> If there are tricks/constructs that I should use for the above steps, I'd<br>
> love to hear them.   Or, of course, if there is some way to obtain variable<br>
> location identifiers from the runtime, that would be great to know as well.<br>
><br>
> Emina<br>
><br>
><br>
><br>
><br>
><br>
> On Wed, Nov 20, 2013 at 5:19 AM, Robby Findler <<a href="mailto:robby@eecs.northwestern.edu">robby@eecs.northwestern.edu</a>><br>
> wrote:<br>
>><br>
>> I didn't try it, but you it might work to use local-expand and then find<br>
>> all the binding forms and then rewrite them to use boxes (or some other<br>
>> source of uniqueness you might have around).<br>
>><br>
>> Robby<br>
>><br>
>><br>
>> On Wed, Nov 20, 2013 at 12:53 AM, Emina Torlak <<a href="mailto:emina@eecs.berkeley.edu">emina@eecs.berkeley.edu</a>><br>
>> wrote:<br>
>>><br>
>>> This is how my solution currently works, but unfortunately, it's not<br>
>>> quite right.  Here is a small example that demonstrates why, assuming the<br>
>>> implementation based on free-id-table:<br>
>>><br>
>>> (define (cell init)<br>
>>>   (let ([x init])<br>
>>>     (case-lambda<br>
>>>       [() x]<br>
>>>       [(v) (set! x v)])))<br>
>>><br>
>>> (define foo (cell 0))<br>
>>> (define bar (cell 1))<br>
>>><br>
>>> > (foo 2)<br>
>>> > (bar 3)<br>
>>> > (foo)<br>
>>> 2<br>
>>> > (bar)<br>
>>> 3<br>
>>> > (dict->list global)<br>
>>> '((.#<syntax:18:17 x> . 3))<br>
>>><br>
>>> In the above scenario, I need the global map to contain two bindings:<br>
>>> one for the location of 'foo.x' and the other for the location of 'bar.x.'<br>
>>><br>
>>> Emina<br>
>>><br>
>>><br>
>>><br>
>>> On Tue, Nov 19, 2013 at 10:31 PM, Sam Tobin-Hochstadt<br>
>>> <<a href="mailto:samth@cs.indiana.edu">samth@cs.indiana.edu</a>> wrote:<br>
>>>><br>
>>>> I think that just identifiers and `free-id-table`s should work here.<br>
>>>> Here's your example:<br>
>>>><br>
>>>> #lang racket<br>
>>>><br>
>>>> (require syntax/id-table (only-in racket [set! #%set!]))<br>
>>>><br>
>>>> (define global (make-free-id-table))<br>
>>>><br>
>>>> (define-syntax-rule (location-of id) #'id)<br>
>>>><br>
>>>> (define-syntax-rule (set! id expr)<br>
>>>>   (let ([v expr])<br>
>>>>     (dict-set! global (location-of id) v)<br>
>>>>     (#%set! id v)))<br>
>>>><br>
>>>> > (define x 1)<br>
>>>> > (set! x 2)<br>
>>>> > (set! x 3)<br>
>>>> > (for/list ([(k v) (in-dict global)]) (list k v))<br>
>>>> '((.#<syntax:4:8 x> 3))<br>
>>>><br>
>>>> Also at <a href="https://gist.github.com/samth/7558673" target="_blank">https://gist.github.com/samth/7558673</a><br>
>>>><br>
>>>> Sam<br>
>>>><br>
>>>> On Mon, Nov 18, 2013 at 2:43 PM, Emina Torlak <<a href="mailto:emina@eecs.berkeley.edu">emina@eecs.berkeley.edu</a>><br>
>>>> wrote:<br>
>>>> > I'm using Racket to implement a language for which I need to track<br>
>>>> > state<br>
>>>> > updates---in particular, variable mutation using set!.  For example,<br>
>>>> > consider this module definition:<br>
>>>> ><br>
>>>> > #lang racket<br>
>>>> ><br>
>>>> > (require (only-in racket [set! #%set!]))<br>
>>>> ><br>
>>>> > (define global (make-hash))<br>
>>>> ><br>
>>>> > (define-syntax-rule (location-of id)<br>
>>>> >   (#%variable-reference id)) ; doesn't quite do the right thing<br>
>>>> ><br>
>>>> > (define-syntax-rule (set! id expr)<br>
>>>> >   (let ([val expr])<br>
>>>> >     (hash-set! global (location-of id) val)<br>
>>>> >     (#%set! id val)))<br>
>>>> ><br>
>>>> > When I evaluate the following sequence of forms against the above<br>
>>>> > definition, I would like the global hash map to contain just one<br>
>>>> > binding<br>
>>>> > that maps the location for 'x' to the value 2.  With the above<br>
>>>> > implementation I get two map entries, since variable-reference doesn't<br>
>>>> > quite<br>
>>>> > do what I hoped it did:<br>
>>>> ><br>
>>>> >> (define x 0)<br>
>>>> >> (set! x 1)<br>
>>>> >> (set! x 2)<br>
>>>> >> x<br>
>>>> > 2<br>
>>>> >> global<br>
>>>> > '#hash((#<variable-reference> . 1) (#<variable-reference> . 2))<br>
>>>> ><br>
>>>> > Is there another construct in Racket that I could use for this<br>
>>>> > purpose?  If<br>
>>>> > not, can something like this be implemented and how much work would it<br>
>>>> > entail?<br>
>>>> ><br>
>>>> > I have a purely macro-based solution that works for the most part, but<br>
>>>> > it's<br>
>>>> > fragile and there are corner cases for which it is just wrong.  So,<br>
>>>> > before<br>
>>>> > trying to fix that, I was wondering if there is a nicer way to solve<br>
>>>> > it by<br>
>>>> > somehow getting handles for variable locations that are comparable<br>
>>>> > using eq?<br>
>>>> > or equal?<br>
>>>> ><br>
>>>> > Thanks!<br>
>>>> ><br>
>>>> > Emina<br>
>>>> ><br>
>>>> ><br>
>>>> > ____________________<br>
>>>> >   Racket Users list:<br>
>>>> >   <a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
>>>> ><br>
>>><br>
>>><br>
>>><br>
>>> ____________________<br>
>>>   Racket Users list:<br>
>>>   <a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
>>><br>
>><br>
><br>
</div></div></blockquote></div><br></div>