[plt-scheme] define-cstruct, mutual dependency

From: Jon Rafkind (workmin at ccs.neu.edu)
Date: Wed Oct 24 01:48:13 EDT 2007

Robert Nikander wrote:
> Hi,
> I'm trying to work with two C structs that use each other in their
> definitions.  I don't see a way to define this with `define-cstruct'.
> struct Object {
>     Class *isa;
> }
> struct Class : Object {
>     const char *name;
>     ...
> }
> This doesn't work, because I can't mention one before the other:
> (define-cstruct _Object ([isa _Class-pointer]))
> (define-cstruct (_Class _Object) ([name _string] ...)
> I'd like to declare the inheritance relation so I can pass classes to
> functions that expect objects.
> Any ideas?
After a lot of futzing around I got this to work

(require (lib "foreign.ss"))(unsafe!)

(define-cstruct _A
        ((x _int)
         (b (_cpointer #f #f (lambda (c) c)
                   (lambda (c) (cpointer-push-tag! c B-tag) c)))))

(define-cstruct (_B _A)
        ((q _int)))

(define lib (ffi-lib "libx"))
(define get (get-ffi-obj "getB" lib (_fun -> _B-pointer)))

(let ((b (get)))
  (printf "~a\n" b)
  (printf "~a\n" (B-q b))
  (printf "~a\n" (A-b b))
  ; (cpointer-push-tag! (A-b b) B-tag)
  ; (set-cpointer-tag! (A-b b) B-tag)
  (printf "a-tag ~a\n" (cpointer-has-tag? (A-b b) A-tag))
  (printf "b-tag ~a\n" (cpointer-has-tag? (A-b b) B-tag))
  (printf "~a\n" (A-b b))
  (printf "eq? ~a\n" (eq? b (A-b b)))
  (printf "~a\n" (B-q (A-b b)))

Where the magic is in (lambda (c) (cpointer-push-tag! c B-tag) c), which
forces the foreign library to treat the returned object as a B type. I
initially tried this
(define-cstruct _A ((x _int) (b (_cpointer #f)))
and then rely on (cpointer-push-tag! (A-b b) B-tag) to set the type, I
have that line commented out above. I'm not entirely sure why that
didn't work.

Also for whatever reason (eq? b (A-b b)) was #f even though the C code did
struct B * b;
b->a.b = b;

but you probably don't need that anyway.

Posted on the users mailing list.