<html><head><meta http-equiv="Content-Type" content="text/html charset=windows-1252"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div>For some reason I tried adding a (with-syntax ([%-stx %] [obj-stx obj]) …) and it actually helped.  </div><div><br></div><div>I have no idea why you would need to do that though.  </div><div><br></div><div><div><font face="Courier New">#lang racket/base (require (for-syntax racket/base))</font></div><div><font face="Courier New"><br></font></div><div><font face="Courier New">(provide object-copy)</font></div><div><font face="Courier New"><br></font></div><div><font face="Courier New">(require racket/class</font></div><div><font face="Courier New">         (for-syntax</font></div><div><font face="Courier New">          syntax/parse))</font></div><div><font face="Courier New"><br></font></div><div><font face="Courier New">(module+ test</font></div><div><font face="Courier New">  (require rackunit))</font></div><div><font face="Courier New"><br></font></div><div><font face="Courier New">(define-syntax object-copy</font></div><div><font face="Courier New">  (lambda (stx)</font></div><div><font face="Courier New">    (syntax-parse stx</font></div><div><font face="Courier New">      [(object-copy %-expr obj-expr</font></div><div><font face="Courier New">                    [field-id:id expr:expr]</font></div><div><font face="Courier New">                    ...)</font></div><div><font face="Courier New">       #:declare %-expr (expr/c #'class? #:name "class")</font></div><div><font face="Courier New">       #:declare obj-expr (expr/c #'(is-a?/c %-expr) #:name "object")</font></div><div><font face="Courier New">       (with-syntax ([ooo '...])</font></div><div><font face="Courier New">         #'(let ([% %-expr.c] [obj obj-expr.c])</font></div><div><font face="Courier New">             (define-values (name field-cnt all-field-syms field-accessor field-mutator super-class skipped?)</font></div><div><font face="Courier New">               (class-info %))</font></div><div><font face="Courier New">             (define remaining-field-syms (remove* '(field-id ...) all-field-syms))</font></div><div><font face="Courier New">             (with-syntax ([%-stx %]</font></div><div><font face="Courier New">                           [obj-stx obj]</font></div><div><font face="Courier New">                           [(remaining-field-id ooo) remaining-field-syms])</font></div><div><font face="Courier New">               (eval-syntax</font></div><div><font face="Courier New">                #'(new %-stx</font></div><div><font face="Courier New">                       [field-id expr] ...</font></div><div><font face="Courier New">                       [remaining-field-id (get-field remaining-field-id obj-stx)] ooo</font></div><div><font face="Courier New">                       )))))]</font></div><div><font face="Courier New">      )))</font></div><div><font face="Courier New"><br></font></div><div><font face="Courier New">(module+ test</font></div><div><font face="Courier New">  (define fish%</font></div><div><font face="Courier New">    (class object% (init-field color weight)</font></div><div><font face="Courier New">      (super-new) (inspect #f)))</font></div><div><font face="Courier New">  </font></div><div><font face="Courier New">  (define marlin (new fish% [color 'orange-and-white] [weight 11]))</font></div><div><font face="Courier New">  </font></div><div><font face="Courier New">  (define dory (object-copy fish% marlin</font></div><div><font face="Courier New">                            [color 'blue]))</font></div><div><font face="Courier New">  </font></div><div><font face="Courier New">  (check-equal? dory (new fish% [color 'blue] [weight 11]))</font></div><div><font face="Courier New">  </font></div><div><font face="Courier New">  (define shark%</font></div><div><font face="Courier New">    (class fish% (init-field weeks-since-eating-fish)</font></div><div><font face="Courier New">      (super-new) (inspect #f)))</font></div><div><font face="Courier New">  </font></div><div><font face="Courier New">  (define bruce (new shark% [color 'grey] [weight 110] [weeks-since-eating-fish 3]))</font></div><div><font face="Courier New">  </font></div><div><font face="Courier New">  (define chum (object-copy shark% bruce</font></div><div><font face="Courier New">                            [weight 90]</font></div><div><font face="Courier New">                            [weeks-since-eating-fish 0]))</font></div><div><font face="Courier New">  </font></div><div><font face="Courier New">  (check-equal? chum (new shark% [color 'grey] [weight 90] [weeks-since-eating-fish 0]))</font></div><div><font face="Courier New">  </font></div><div><font face="Courier New">  (define not-really-chum</font></div><div><font face="Courier New">    (object-copy fish% bruce</font></div><div><font face="Courier New">                 [weight 90]))</font></div><div><font face="Courier New">  </font></div><div><font face="Courier New">  (check-equal? not-really-chum (new fish% [color 'grey] [weight 90]))</font></div><div><font face="Courier New">  </font></div><div><font face="Courier New">  )</font></div></div><br><div><div>On Apr 18, 2014, at 11:45 PM, Greg Hendershott <<a href="mailto:greghendershott@gmail.com">greghendershott@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite">Although I have hardly any experience with racket/class, and I'm not<br>very knowledgeable about how Racket structs are implemented, this got<br>me curious to look at how struct-copy is implemented.<br><br>First, your macro appears to be trying to work around the problem that<br>`get-field-names` only makes sense at runtime (when given some<br>particular object at runtime) -- but your macro is at compile-time.<br>That's probably why you tried the nested `(with-syntax #'(<br>(with-syntax (eval-syntax #'(  )))))`.<br><br><blockquote type="cite">And also, is there another version of field-names that takes a class instead<br>of an object, because I think that will create another problem when I get to<br>the last test (with not-really-chum).<br></blockquote><br>`class-info` looks promising for that. If only you could get a<br>`class?` at compile time. But I haven't figured out how.<br><br>Racket struct identifiers have a meaning both at run time (as a<br>constructor) and at compile time (as a transformer binding to struct<br>info):<br><br>"5.7 Structure Type Transformer Binding<br><br>The struct form binds the name of a structure type as a transformer<br>binding that records the other identifiers bound to the structure<br>type, the constructor procedure, the predicate procedure, and the<br>field accessor and mutator procedures. This information can be used<br>during the expansion of other expressions via syntax-local-value."<br><br>As a result, struct-copy can use syntax-local-value to get the<br>compile-time value, and pass it to extract-struct-info, to get a list<br>of field identifiers.<br><br>But unfortunately a class identifier does not seem to have any<br>syntax-local-value at all (much less one that you could pass to<br>class-info).<br><br>That's my attempt at figuring it out. Hopefully one of the Racket<br>experts can give you an actual solution (and/or correct any of what I<br>wrote here).<br></blockquote></div><br></body></html>