[racket] Structs and syntax-local-value ... how is the struct name overloaded? (Greg Hendershott)

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Mon Jan 20 22:18:27 EST 2014

Scott, if you are old enough, this should remind you of the 'use a collection of structs instead of parallel collections' guideline. In the olden days of 1990 and before, programmers still used two vectors of numbers to represents 2D points instead of one vector of 2-field structs. Separating the procedure from the info via a hash can pose the same kind of SE problems as this old trick. -- Matthias







On Jan 20, 2014, at 6:51 PM, Carl Eastlund wrote:

> But the hash table only needs to exist in one place, it doesn't need to be bound in each namespace.  Anything that needs to get at metadata for bindings just looks at the hash table directly, not via syntax-local-value of some identifier.
> 
> Carl Eastlund
> 
> 
> On Mon, Jan 20, 2014 at 6:49 PM, Scott Klarenbach <scott at pointyhat.ca> wrote:
> Using a binding that carries everything with it, or using a syntax-time hash table that carries out of band data that can be looked up based on the original binding, is reliable. 
> 
> Good point, Sam made it at the same time.  :)
> 
> Wouldn't a syntax-time hash-table introduce problems as well since there's no guarantee it gets copied over either?
> 
> 
> 
> On Mon, Jan 20, 2014 at 3:35 PM, Carl Eastlund <carl.eastlund at gmail.com> wrote:
> But there's no guarantee that if someone imports the original name somewhere, renames it somehow, etc., that they'll copy over a <name>-META binding as well.  Using a binding that carries everything with it, or using a syntax-time hash table that carries out of band data that can be looked up based on the original binding, is reliable.  Using an extra binding that _should_ be there in most namespaces, can be broken by contexts you have no control over.
> 
> Carl Eastlund
> 
> 
> On Mon, Jan 20, 2014 at 6:31 PM, Scott Klarenbach <scott at pointyhat.ca> wrote:
> If/when it does matter, instead you could use a hashtable on the side,
> mapping from the procedure to the info. Of course that way, you need
> to use `(lookup thing)` to get the info.
> 
> Not to mention that it's vastly simpler to do it this way.  You get a straightforward transformer proc and a hashtable bound as syntax.
> 
> This is partly a learning exercise for me - so it's valuable to go through - but the more I look at it the more I think it's a lot of complexity just to be able to overload the struct name, when it would suffice for match and other macros that wanted compile-time meta info to follow a convention like struct-name-META or something.  Afterall, structs already come with a lot of magical bindings that you have to learn by convention, what's one more?
> 
> Just my two cents.
> 
> sk
> 
> 
> On Mon, Jan 20, 2014 at 1:41 PM, <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: Structs and syntax-local-value ... how is the struct name
>       overloaded? (Carl Eastlund)
>    2. Re: Structs and syntax-local-value ... how is the struct name
>       overloaded? (Greg Hendershott)
> 
> 
> ----------------------------------------------------------------------
> 
> Message: 1
> Date: Mon, 20 Jan 2014 13:00:35 -0500
> From: Carl Eastlund <carl.eastlund at gmail.com>
> To: "Alexander D. Knauth" <alexander at knauth.org>
> Cc: Scott Klarenbach <scott at pointyhat.ca>, Racket mailing list
>         <users at racket-lang.org>
> Subject: Re: [racket] Structs and syntax-local-value ... how is the
>         struct name overloaded?
> Message-ID:
>         <CAEOPtY09_5EUFpOn6uYBcJAB+TXTdDk=EK-DUHbLU2wu=XzDZw at mail.gmail.com>
> Content-Type: text/plain; charset="utf-8"
> 
> Yes, that's exactly it.
> 
> Carl Eastlund
> 
> 
> On Mon, Jan 20, 2014 at 10:13 AM, Alexander D. Knauth
> <alexander at knauth.org>wrote:
> 
> > I'm just curious, is this what you mean?
> >
> > #lang racket
> >
> > (require rackunit
> >          (for-syntax
> >           syntax/parse))
> >
> > (begin-for-syntax
> >   (struct proc-with-info (proc info) #:property prop:procedure
> > (struct-field-index proc)))
> >
> > (define-syntax thing
> >   (proc-with-info (lambda (stx)
> >                     (syntax-parse stx #:literals (thing)
> >                                   [(thing x ...)
> >                                    #'(#%app thing x ...)]
> >                                   [thing
> >                                    #'(lambda (x) x)]))
> >                   'info))
> >
> > (define-syntax get-info
> >   (lambda (stx)
> >     (syntax-parse stx
> >                   [(get-info x)
> >                    (datum->syntax stx `(quote ,(proc-with-info-info
> > (syntax-local-value #'x))))])))
> >
> > (check-equal? (thing 1) 1)
> > (let ([x (random)])
> >   (check-equal? (thing x) x))
> >
> > (check-equal? (get-info thing)
> >               'info)
> >
> >
> > On Jan 20, 2014, at 12:37 AM, Carl Eastlund wrote:
> >
> > It sounds like you've got it.  A syntax transformer must be a procedure,
> > and prop:procedure is how you make a procedure that can also be something
> > else.  So if you want something to be both a syntax transformer and a
> > struct binding, for instance, you need to use prop:procedure and
> > prop:struct-info.  You can't make something both a procedure and a symbol,
> > because symbols don't work via struct properties, but you could make it
> > both a procedure and a struct that contains a symbol.
> >
> > Carl Eastlund
> >
> > On Mon, Jan 20, 2014 at 12:21 AM, Scott Klarenbach <scott at pointyhat.ca>wrote:
> >
> >>  That doesn't look like a complete program; what does #'done refer to?
> >>> And where did the "val is: " printout go?
> >>
> >>
> >> That's just a quick hack for illustration purposes.  #''done is just
> >> something to return. (note the two quotes)  The output is:
> >> val is: #<procedure:self-ctor-checked-struct-info>#<procedure:posn>
> >> 'done
> >>
> >> But your supposition is correct: posn is always bound as syntax to a
> >>> self-ctor-checked-struct-info-object.  That object works as a syntax
> >>> transformer; run time references to posn are transformed into references to
> >>> the actual procedure value you're seeing as #<procedure:posn>.
> >>
> >>
> >> Thanks Carl, it's starting to make sense.  So the prop:procedure of the
> >> struct is actually the transformer?  And so in expression context it acts
> >> as a macro, but in syntax-local-value context it acts as a struct?  I was
> >> trying to produce something similar, but ran into the following issues:
> >>
> >> Say I want (define-syntax (posn) ...) to transform syntax, but I also
> >> want (syntax-local-value #'posn) to return 'something.
> >> Without the struct trick I can only have one but not the other.  I could
> >> either have (define-syntax posn 'something), and lose the ability to call
> >> it as a macro (illegal syntax), or have (define-syntax (posn) #'something),
> >> and then (syntax-local-value #'posn) returns the transformer, rather than
> >> 'something.
> >>
> >>
> >>
> >>
> >>
> >> On Sun, Jan 19, 2014 at 8:57 PM, Scott Klarenbach <scott at pointyhat.ca>wrote:
> >>
> >>> It's not changing it, I'm just trying to figure out the implementation
> >>> and understand what I'm seeing.
> >>> For example, given this:
> >>>
> >>> (struct posn (x y))
> >>>
> >>> (define-syntax (test stx)
> >>>   (syntax-case stx ()
> >>> [(_ x)
> >>>  (printf "val is: ~s" (syntax-local-value #'posn))
> >>>  #''done]))
> >>>
> >>> > posn
> >>> #<procedure:posn>
> >>>
> >>> > (test x)
> >>> #<procedure:self-ctor-checked-struct-info>
> >>>
> >>> I'm surprised that the values are different.  Is posn actually always a
> >>> self-ctor-checked-struct-info object, but it's prop:procedure is defined to
> >>> allow for being used in an expression in the first case?
> >>>
> >>>
> >>>
> >>>
> >>> On Sun, Jan 19, 2014 at 8:40 PM, Carl Eastlund <carl.eastlund at gmail.com>wrote:
> >>>
> >>>> If syntax-local-value is returning something other than the value you
> >>>> put in, that's a bug.  It shouldn't be wrapping it or changing it in any
> >>>> way.  Do you have a program where you bind something via define-syntax that
> >>>> satisfies struct-info?, and get something out via syntax-local-value that
> >>>> doesn't?
> >>>>
> >>>> Carl Eastlund
> >>>>
> >>>> On Sun, Jan 19, 2014 at 11:27 PM, Scott Klarenbach <scott at pointyhat.ca>wrote:
> >>>>
> >>>>> But I don't see how the same binding can be a transformer and also
> >>>>> return something else (like a list, or a checked-struct-info-thing) via
> >>>>> syntax-local-value.
> >>>>>
> >>>>> If I bind my-fn as a transformer, then any other macros that use it
> >>>>> with syntax-local-value will receive the transformer procedure back, not
> >>>>> any special meta data.  And if I bind it as meta data directly, ie
> >>>>> (define-syntax my-fn 'something) then it works with syntax-local-value but
> >>>>> any attempts to use it as a transformer result in illegal syntax.
> >>>>>
> >>>>> Even if I create a transformer that returns a struct which implements
> >>>>> both prop:procedure and prop:struct-info, using that binding with
> >>>>> syntax-local-value will return the transformer procedure itself, rather
> >>>>> than the final struct.
> >>>>>
> >>>>>
> >>>>>
> >>>>> On Sun, Jan 19, 2014 at 8:04 PM, Carl Eastlund <
> >>>>> carl.eastlund at gmail.com> wrote:
> >>>>>
> >>>>>> Yes, I believe that the name of a structure defined by "struct" is
> >>>>>> bound at syntax-time to a value that implements both prop:procedure, so
> >>>>>> that it can expand to a use of the constructor when used in an expression,
> >>>>>> and prop:struct-info so that it can be use to look up static information
> >>>>>> when passed to relevant macros.
> >>>>>>
> >>>>>> Carl Eastlund
> >>>>>>
> >>>>>>
> >>>>>> On Sun, Jan 19, 2014 at 11:00 PM, Scott Klarenbach <
> >>>>>> scott at pointyhat.ca> wrote:
> >>>>>>
> >>>>>>> How is it that the definition of (struct my-name (x y)) can bind
> >>>>>>> *my-name* both as a #<procedure:my-name> at runtime and a
> >>>>>>> transformer-binding *my-name* that at compile time (via
> >>>>>>> syntax-local-value) produces #<procedure:self-ctor-checked-struct-info>.?
> >>>>>>>
> >>>>>>> Or, put another way, how can I define a transformer *my-fn* that
> >>>>>>> produces syntax, but that also exposes hidden meta-data under the same
> >>>>>>> binding to other macros that might wish to know about the binding at
> >>>>>>> compile time?
> >>>>>>>
> >>>>>>> I'm specifically wondering how the overloading works.  Is it some
> >>>>>>> clever use of prop:procedure?
> >>>>>>>
> >>>>>>> Thanks.
> >>>>>>>
> >>>>>>> --
> >>>>>>> Talk to you soon,
> >>>>>>>
> >>>>>>> Scott Klarenbach
> >>>>>>>
> >>>>>>> PointyHat Software Corp.
> >>>>>>> www.pointyhat.ca
> >>>>>>> p 604-568-4280
> >>>>>>> e scott at pointyhat.ca
> >>>>>>> 200-1575 W. Georgia
> >>>>>>> Vancouver, BC V6G2V3
> >>>>>>>
> >>>>>>> _______________________________________
> >>>>>>> To iterate is human; to recur, divine
> >>>>>>>
> >>>>>>> ____________________
> >>>>>>>   Racket Users list:
> >>>>>>>   http://lists.racket-lang.org/users
> >>>>>>>
> >>>>>>>
> >>>>>>
> >>>>>
> >>>>>
> >>>>> --
> >>>>> Talk to you soon,
> >>>>>
> >>>>> Scott Klarenbach
> >>>>>
> >>>>> PointyHat Software Corp.
> >>>>> www.pointyhat.ca
> >>>>> p 604-568-4280
> >>>>> e scott at pointyhat.ca
> >>>>> 200-1575 W. Georgia
> >>>>> Vancouver, BC V6G2V3
> >>>>>
> >>>>> _______________________________________
> >>>>> To iterate is human; to recur, divine
> >>>>>
> >>>>
> >>>>
> >>>
> >>>
> >>> --
> >>> Talk to you soon,
> >>>
> >>> Scott Klarenbach
> >>>
> >>> PointyHat Software Corp.
> >>> www.pointyhat.ca
> >>> p 604-568-4280
> >>> e scott at pointyhat.ca
> >>> 200-1575 W. Georgia
> >>> Vancouver, BC V6G2V3
> >>>
> >>> _______________________________________
> >>> To iterate is human; to recur, divine
> >>>
> >>
> >>
> >>
> >> --
> >> Talk to you soon,
> >>
> >> Scott Klarenbach
> >>
> >> PointyHat Software Corp.
> >> www.pointyhat.ca
> >> p 604-568-4280
> >> e scott at pointyhat.ca
> >> 200-1575 W. Georgia
> >> Vancouver, BC V6G2V3
> >>
> >> _______________________________________
> >> To iterate is human; to recur, divine
> >>
> >
> > ____________________
> >  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/20140120/1cbff376/attachment-0001.html>
> 
> ------------------------------
> 
> Message: 2
> Date: Mon, 20 Jan 2014 16:40:56 -0500
> From: Greg Hendershott <greghendershott at gmail.com>
> To: users at racket-lang.org
> Subject: Re: [racket] Structs and syntax-local-value ... how is the
>         struct name overloaded?
> Message-ID:
>         <CAGspUn3DeoWR7Qfw=uPamDuV+6ig9asRt=-DcAjh+uViBbTYnA at mail.gmail.com>
> Content-Type: text/plain; charset=ISO-8859-1
> 
> >> and prop:procedure is how you make a procedure that can also be something
> >> else.
> 
> One thing to keep in mind is that there is _some_ overhead. In my
> recent experience, applying via prop:procedure took roughly 1.6X the
> time as applying a plain procedure. (This with the variant of
> prop:procedure where its value is an index to the field in the struct
> holding the procedure.)
> 
> I don't know how much of the extra time is due to memory reference,
> missing the optimizer, and/or other?
> 
> For many applications that doesn't matter, and it's worth it to have
> `thing` self-evaluate to the info.
> 
> If/when it does matter, instead you could use a hashtable on the side,
> mapping from the procedure to the info. Of course that way, you need
> to use `(lookup thing)` to get the info.
> 
> 
> End of users Digest, Vol 101, Issue 60
> **************************************
> 
> 
> 
> -- 
> Talk to you soon,
> 
> Scott Klarenbach
> 
> PointyHat Software Corp.
> www.pointyhat.ca
> p 604-568-4280
> e scott at pointyhat.ca
> 200-1575 W. Georgia
> Vancouver, BC V6G2V3
> 
> _______________________________________
> To iterate is human; to recur, divine
> 
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users
> 
> 
> 
> 
> 
> -- 
> Talk to you soon,
> 
> Scott Klarenbach
> 
> PointyHat Software Corp.
> www.pointyhat.ca
> p 604-568-4280
> e scott at pointyhat.ca
> 200-1575 W. Georgia
> Vancouver, BC V6G2V3
> 
> _______________________________________
> To iterate is human; to recur, divine
> 
> ____________________
>  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/20140120/86a1fa84/attachment-0001.html>

Posted on the users mailing list.