[Prev][Next][Index][Thread]

Re: Using C structs with FD 2.0 FFI



> Hello all,
>
> So far I have been very impressed with the Harlequin Dylan C FFI.  But I
> have started playing with structs now and am having a problem getting a
> simple example to work.  When I try to run the Dylan code below, I get a
> "Dylan error: No next method" error. [...]

I think the problem is that stats isn't an output parameter as such (i.e.
you're not doing *stats = my_stats_struct anywhere in the function)[*].
ReadStats() expects to receive a pointer to a pre-allocated structure and 
all it does is modify that struct with a new value for count.

So step one is to remove the "output" adjective from the function 
declaration:

define C-function read-stats
  parameter stats :: <Statistics*>;
  result value :: <C-int>;
  c-name: "ReadStats"
end;

Step two is to allocate a structure and pass it in:

define method main () => ()
  format-out("started...\n");
  with-stack-structure (stats :: <Statistics*>)
    let result = read-stats(stats); // now only returns one value
    format-out("stats %=\n", stats.count); 
  end;
end method main;

As the name of the macro suggests, with-stack-structure allocates a 
temporary struct live only within the macro. Use make(<Statistics*>)
and delete(stats) for manual control over the lifetime of the struct.

Hope this helps,

-- Keith

[*] I guess the uninformative no next method error is a result of the 
implementation trying to dereference a pointer to a struct (to extract 
the output value) when it doesn't actually support manipulating structs by 
value in this situation.

> -------------------- C code --------------------
> typedef struct {
>   double count;
> } Statistics;
>
> int ReadStats (Statistics* stats) {
>   stats->count = 123;
>   return 1;
> }
>
> -------------------- Dylan code --------------------
> define C-struct <Statistics>
>   slot count :: <C-double>;
>   pointer-type-name: <Statistics*>;
> end;
>
> define C-function read-stats
>   output parameter stats :: <Statistics*>;
>   result value :: <C-int>;
>   c-name: "ReadStats"
> end;
>
> define method main () => ()
>   format-out("started...\n");
>   let (result, stats) = read-stats();
>   format-out("stats %=\n", stats.count);
> end method main;