caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Wrapping OCaml function returning a variant
@ 2007-03-28 11:33 Joel Reymont
  2007-03-28 11:47 ` [Caml-list] " Richard Jones
                   ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Joel Reymont @ 2007-03-28 11:33 UTC (permalink / raw)
  To: Caml List

Is there an example of returning a variant from OCaml into C somewhere?

It's a regular variant, declared like this

type morpher_output =
   | Success of string
   | Error of string * int * int * int

The other issue is that I don't know how to deal with strings  
allocated in OCaml. Will they be  collected automatically?

The strings _must_ be allocated in OCaml but I can guarantee that  
they will not be modified in the C code. Any suggestions on how to  
deal with this?

	Thanks, Joel

--
http://wagerlabs.com/






^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] Wrapping OCaml function returning a variant
  2007-03-28 11:33 Wrapping OCaml function returning a variant Joel Reymont
@ 2007-03-28 11:47 ` Richard Jones
  2007-03-28 12:25 ` micha
  2007-03-28 12:55 ` Serge Aleynikov
  2 siblings, 0 replies; 16+ messages in thread
From: Richard Jones @ 2007-03-28 11:47 UTC (permalink / raw)
  To: Joel Reymont; +Cc: Caml List

On Wed, Mar 28, 2007 at 12:33:46PM +0100, Joel Reymont wrote:
> The other issue is that I don't know how to deal with strings  
> allocated in OCaml. Will they be  collected automatically?
> 
> The strings _must_ be allocated in OCaml but I can guarantee that  
> they will not be modified in the C code. Any suggestions on how to  
> deal with this?

String_val (ocaml_str) will give you a pointer to the bytes in the
string.  It's even ASCIIZ (ie. ASCII NUL-terminated) so you can
directly use C str* functions on it.

There are two catches: The small one is that OCaml strings may contain
NUL characters internally, which is obviously not allowed in C
strings, so you have to either guarantee on the OCaml side that this
won't be the case, or else go through hoops on the C side.

The bigger catch is that the garbage collector can and will move the
string around whenever it likes.  So if you save the pointer from
String_val, go back into OCaml code and back into C, and try to reuse
the saved pointer, it won't necessarily point to the string any more.
The string might even have been freed by the GC.  If you want to do
that, either rewrite your code so it doesn't save the pointer like
this, strdup the string to make a private copy in C, or register a
global root.

Rich.

-- 
Richard Jones
Red Hat


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] Wrapping OCaml function returning a variant
  2007-03-28 12:55 ` Serge Aleynikov
@ 2007-03-28 12:01   ` Joel Reymont
  2007-03-28 13:40     ` Serge Aleynikov
  2007-03-28 12:13   ` Joel Reymont
  1 sibling, 1 reply; 16+ messages in thread
From: Joel Reymont @ 2007-03-28 12:01 UTC (permalink / raw)
  To: Serge Aleynikov; +Cc: Caml List


On Mar 28, 2007, at 1:55 PM, Serge Aleynikov wrote:

> You can read the section 18.3.4 of http://caml.inria.fr/pub/docs/ 
> manual-ocaml/manual032.html

It does not clearly explain how to handle variant types in C code.  
Maybe I'm dumb but I did not understand it.

> Then if still unclear, examine: http://oracaml.sourceforge.net/
> or any other C-interface library available on Caml Hump: http:// 
> caml.inria.fr/cgi-bin/hump.en.cgi?sort=0&browse=65

It looks like you are using polymorphic variants in new syntax. Maybe  
I'm wrong but it doesn't work for me

# type foo = [Null | Int of int];;
Syntax error

I still don't understand how I can handle regular variants of the  
following type returned by OCaml to the C side

> type morpher_output =
>   | Success of string
>   | Error of string * int * int * int

	Thanks, Joel

--
http://wagerlabs.com/






^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] Wrapping OCaml function returning a variant
  2007-03-28 12:55 ` Serge Aleynikov
  2007-03-28 12:01   ` Joel Reymont
@ 2007-03-28 12:13   ` Joel Reymont
  2007-03-28 13:53     ` Serge Aleynikov
  1 sibling, 1 reply; 16+ messages in thread
From: Joel Reymont @ 2007-03-28 12:13 UTC (permalink / raw)
  To: Serge Aleynikov; +Cc: Caml List


On Mar 28, 2007, at 1:55 PM, Serge Aleynikov wrote:

> If you are using caml_copy_string() or caml_alloc_string() they  
> allocate strings on OCaml's heap, and will be automatically garbage  
> collected.

How do I pass a C string into OCaml if the assumption is that it will  
not be modified? Do I still need to copy it with caml_copy_string?

I don't think I need to allocate strings on the OCaml heap from C as  
the string given to OCaml will be allocated on the C heap and the  
string returned from OCaml will be garbage-collected automatically.

	Thanks, Joel

--
http://wagerlabs.com/






^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] Wrapping OCaml function returning a variant
  2007-03-28 11:33 Wrapping OCaml function returning a variant Joel Reymont
  2007-03-28 11:47 ` [Caml-list] " Richard Jones
@ 2007-03-28 12:25 ` micha
  2007-03-28 12:51   ` Joel Reymont
  2007-03-28 12:55 ` Serge Aleynikov
  2 siblings, 1 reply; 16+ messages in thread
From: micha @ 2007-03-28 12:25 UTC (permalink / raw)
  To: caml-list

Am Wed, 28 Mar 2007 12:33:46 +0100
schrieb Joel Reymont <joelr1@gmail.com>:

> Is there an example of returning a variant from OCaml into C
> somewhere?
> 
> It's a regular variant, declared like this
> 
> type morpher_output =
>    | Success of string
>    | Error of string * int * int * int
> 

the labels are numbered starting from zero, so in c have have to
decode two possible values :

let a= Success("xxx") ...

is in C a block with tag 0 and size 1, to get the string write:

char* s = String_val(Field(a,0))

for the case

let b = Error("e",1,2,3) ...

you have a block with tag 1 and size 4:
to get the values you write:
char* err=String_val(Field(b,0));
int n1= Int_val(Field(b,1));
...
int n3= Int_val(Field(b,3));


hope that helps...

 Michael


ps: polymorphic variants are handled different...


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] Wrapping OCaml function returning a variant
  2007-03-28 12:25 ` micha
@ 2007-03-28 12:51   ` Joel Reymont
  2007-03-28 13:28     ` Richard Jones
  2007-03-28 14:34     ` micha
  0 siblings, 2 replies; 16+ messages in thread
From: Joel Reymont @ 2007-03-28 12:51 UTC (permalink / raw)
  To: micha; +Cc: caml-list

One last question which I couldn't answer by browsing through  
mltypes.h...

What is the type of a on the C side?

	Thanks, Joel

On Mar 28, 2007, at 1:25 PM, micha wrote:

> the labels are numbered starting from zero, so in c have have to
> decode two possible values :
>
> let a= Success("xxx") ...
>
> is in C a block with tag 0 and size 1, to get the string write:
>
> char* s = String_val(Field(a,0))

--
http://wagerlabs.com/






^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] Wrapping OCaml function returning a variant
  2007-03-28 11:33 Wrapping OCaml function returning a variant Joel Reymont
  2007-03-28 11:47 ` [Caml-list] " Richard Jones
  2007-03-28 12:25 ` micha
@ 2007-03-28 12:55 ` Serge Aleynikov
  2007-03-28 12:01   ` Joel Reymont
  2007-03-28 12:13   ` Joel Reymont
  2 siblings, 2 replies; 16+ messages in thread
From: Serge Aleynikov @ 2007-03-28 12:55 UTC (permalink / raw)
  To: Joel Reymont; +Cc: Caml List

Joel Reymont wrote:
> Is there an example of returning a variant from OCaml into C somewhere?
> It's a regular variant, declared like this
> 
> type morpher_output =
>   | Success of string
>   | Error of string * int * int * int

You can read the section 18.3.4 of 
http://caml.inria.fr/pub/docs/manual-ocaml/manual032.html

Then if still unclear, examine: http://oracaml.sourceforge.net/
or any other C-interface library available on Caml Hump: 
http://caml.inria.fr/cgi-bin/hump.en.cgi?sort=0&browse=65

> The other issue is that I don't know how to deal with strings allocated 
> in OCaml. Will they be  collected automatically?

If you are using caml_copy_string() or caml_alloc_string() they allocate 
strings on OCaml's heap, and will be automatically garbage collected.

> The strings _must_ be allocated in OCaml but I can guarantee that they 
> will not be modified in the C code. Any suggestions on how to deal with 
> this?

Unless I am not understanding your question, the above two functions are 
the way to allocate strings on OCaml's heap.

Serge


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] Wrapping OCaml function returning a variant
  2007-03-28 12:51   ` Joel Reymont
@ 2007-03-28 13:28     ` Richard Jones
  2007-03-28 14:34     ` micha
  1 sibling, 0 replies; 16+ messages in thread
From: Richard Jones @ 2007-03-28 13:28 UTC (permalink / raw)
  To: Joel Reymont; +Cc: caml-list

On Wed, Mar 28, 2007 at 01:51:39PM +0100, Joel Reymont wrote:
> One last question which I couldn't answer by browsing through  
> mltypes.h...
> 
> What is the type of a on the C side?

'value'.

Rich.

-- 
Richard Jones
Red Hat


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] Wrapping OCaml function returning a variant
  2007-03-28 12:01   ` Joel Reymont
@ 2007-03-28 13:40     ` Serge Aleynikov
  0 siblings, 0 replies; 16+ messages in thread
From: Serge Aleynikov @ 2007-03-28 13:40 UTC (permalink / raw)
  To: Joel Reymont; +Cc: Caml List

Joel Reymont wrote:
> 
> On Mar 28, 2007, at 1:55 PM, Serge Aleynikov wrote:
> 
>> You can read the section 18.3.4 of 
>> http://caml.inria.fr/pub/docs/manual-ocaml/manual032.html
> 
> It does not clearly explain how to handle variant types in C code. Maybe 
> I'm dumb but I did not understand it.
> 
>> Then if still unclear, examine: http://oracaml.sourceforge.net/
>> or any other C-interface library available on Caml Hump: 
>> http://caml.inria.fr/cgi-bin/hump.en.cgi?sort=0&browse=65
> 
> It looks like you are using polymorphic variants in new syntax. Maybe 
> I'm wrong but it doesn't work for me
> 
> # type foo = [Null | Int of int];;
> Syntax error

That's because this code is written using revised 
(http://caml.inria.fr/pub/docs/tutorial-camlp4/tutorial005.html) syntax. 
  These are not polymorphic variants but rather a basic union type with 
non-constant constructors.

Hint: you can start the ocaml toplevel like this to get it understand 
revised syntax: "ocaml camlp4r.cma".

 > I still don't understand how I can handle regular variants of the
 > following type returned by OCaml to the C side

In terms of your example above, on the C side you would do:

void bar(value foo) {
   if (Is_long(foo)) {
      switch (Long_val(foo)) {
        case 0: /* Null */
          ...
          break;
        /* if there are other constant constructors besides Null
           add additional cases here */
        default:
          fail_exception(Long_val(foo), "Unknown constant constructor!");
      }
   } else {
      switch (Tag_val(foo)) {
        case 0:  /* Int of int */
          /* Access the non-constant value by Long_val(Field(foo,0))) */
          break;
        ...
      }
   }
}

Regards,

Serge


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] Wrapping OCaml function returning a variant
  2007-03-28 12:13   ` Joel Reymont
@ 2007-03-28 13:53     ` Serge Aleynikov
  0 siblings, 0 replies; 16+ messages in thread
From: Serge Aleynikov @ 2007-03-28 13:53 UTC (permalink / raw)
  To: Joel Reymont; +Cc: Caml List

Joel Reymont wrote:
> 
> On Mar 28, 2007, at 1:55 PM, Serge Aleynikov wrote:
> 
>> If you are using caml_copy_string() or caml_alloc_string() they 
>> allocate strings on OCaml's heap, and will be automatically garbage 
>> collected.
> 
> How do I pass a C string into OCaml if the assumption is that it will 
> not be modified? Do I still need to copy it with caml_copy_string?

If you need to be able to access your C string value from OCaml, 
caml_copy_string is what you need.  OTOH, if you want the string to be 
passed to OCaml as an opaque type (in which case OCaml won't be able to 
access its value directly, though the value will live on the C heap and 
can only be accessible from C) you can pass the string pointer using a 
Custom block (see section 18.9.2 
http://caml.inria.fr/pub/docs/manual-ocaml/manual032.html).

Regards,

Serge


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] Wrapping OCaml function returning a variant
  2007-03-28 12:51   ` Joel Reymont
  2007-03-28 13:28     ` Richard Jones
@ 2007-03-28 14:34     ` micha
  2007-03-28 14:46       ` Joel Reymont
  1 sibling, 1 reply; 16+ messages in thread
From: micha @ 2007-03-28 14:34 UTC (permalink / raw)
  To: caml-list

Am Wed, 28 Mar 2007 13:51:39 +0100
schrieb Joel Reymont <joelr1@gmail.com>:

> One last question which I couldn't answer by browsing through  
> mltypes.h...
> 
> What is the type of a on the C side?

that may look like:

CAMLprim value cfunc(value x)
{
CAMLparam1(x);
switch (Tag_val(x)) {
	case 0: do something with first variant;
	case 1: do something  with second variant
	default: argh;
}
CAMLreturn(Val_unit);
}


 Michael


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] Wrapping OCaml function returning a variant
  2007-03-28 14:34     ` micha
@ 2007-03-28 14:46       ` Joel Reymont
  2007-03-28 14:56         ` micha
  2007-03-28 14:57         ` Xavier Leroy
  0 siblings, 2 replies; 16+ messages in thread
From: Joel Reymont @ 2007-03-28 14:46 UTC (permalink / raw)
  To: micha; +Cc: caml-list

I came up with this. Is it sound?

char *morph(char *code, char** error, int *line, int *start, int *end)
{
   static value *closure = NULL;
   value v;
   char *res;

   if (closure == NULL)
     closure = caml_named_value("morph");

   v = callback(*closure, caml_copy_string(code));

   switch (Long_val(v)) {
   case 0: /* success */
     res = String_val(Field(v, 0));
     *error = NULL;
   case 1: /* error  */
     res = NULL;
     *error = String_val(Field(v, 0));
     *line = Int_val(Field(v, 1));
     *start = Int_val(Field(v, 2));
     *end = Int_val(Field(v, 3));
   }

   return res;
}

	Thanks, Joel

On Mar 28, 2007, at 3:34 PM, micha wrote:

> that may look like:
>
> CAMLprim value cfunc(value x)
> {
> CAMLparam1(x);
> switch (Tag_val(x)) {
> 	case 0: do something with first variant;
> 	case 1: do something  with second variant
> 	default: argh;
> }
> CAMLreturn(Val_unit);
> }

--
http://wagerlabs.com/






^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] Wrapping OCaml function returning a variant
  2007-03-28 14:46       ` Joel Reymont
@ 2007-03-28 14:56         ` micha
  2007-03-28 14:57         ` Xavier Leroy
  1 sibling, 0 replies; 16+ messages in thread
From: micha @ 2007-03-28 14:56 UTC (permalink / raw)
  To: Joel Reymont; +Cc: caml-list

Am Wed, 28 Mar 2007 15:46:54 +0100
schrieb Joel Reymont <joelr1@gmail.com>:

> I came up with this. Is it sound?
> 
> 
>    switch (Long_val(v)) {

I think you must use Tag_val(x) since your datatype is a constructed
type with parameters (it is a block not an integer as for :
type x = One | Two, here you would have integers )

>    case 0: /* success */
>      res = String_val(Field(v, 0));

maybe it's better to strcpy() the string if you want to be independent
of the ocaml side


cheers
 Michael


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] Wrapping OCaml function returning a variant
  2007-03-28 14:46       ` Joel Reymont
  2007-03-28 14:56         ` micha
@ 2007-03-28 14:57         ` Xavier Leroy
  2007-03-28 15:07           ` Joel Reymont
  1 sibling, 1 reply; 16+ messages in thread
From: Xavier Leroy @ 2007-03-28 14:57 UTC (permalink / raw)
  To: Joel Reymont; +Cc: micha, caml-list

> I came up with this. Is it sound?

Not quite.

> char *morph(char *code, char** error, int *line, int *start, int *end)
> {
>   static value *closure = NULL;
>   value v;
>   char *res;
>
>   if (closure == NULL)
>     closure = caml_named_value("morph");
>
>   v = callback(*closure, caml_copy_string(code));

Here, caml_copy_string could trigger a GC and move the closure pointed
to by closure, so the value of *closure could become invalid.
You need to order the computations explicitly:

    value vcode;
    if (closure == NULL)
      closure = caml_named_value("morph");
    vcode = caml_copy_string(code);
    v = callback(*closure, vcode);

>   switch (Long_val(v)) {

v is not a constant constructor, but a constructor with arguments.
So, its representation is not an integer, but a pointer to a block.
You want to discriminate on the tag of this block.

    switch (Tag_val(v)) {


>   case 0: /* success */
>     res = String_val(Field(v, 0));
>     *error = NULL;
>   case 1: /* error  */
>     res = NULL;
>     *error = String_val(Field(v, 0));
>     *line = Int_val(Field(v, 1));
>     *start = Int_val(Field(v, 2));
>     *end = Int_val(Field(v, 3));
>   }

The next GC can move the strings obtained by String_val, making
invalid the pointer you return or store in *error.  Take a copy immediately:

    switch (Tag_val(v)) {
    case 0: /* success */
      res = strdup(String_val(Field(v, 0)));
      *error = NULL;
    case 1: /* error  */
      res = NULL;
      *error = strdup(String_val(Field(v, 0)));
      *line = Int_val(Field(v, 1));
      *start = Int_val(Field(v, 2));
      *end = Int_val(Field(v, 3));
    }

Hope this helps,

- Xavier Leroy


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] Wrapping OCaml function returning a variant
  2007-03-28 14:57         ` Xavier Leroy
@ 2007-03-28 15:07           ` Joel Reymont
  2007-03-28 22:47             ` Joel Reymont
  0 siblings, 1 reply; 16+ messages in thread
From: Joel Reymont @ 2007-03-28 15:07 UTC (permalink / raw)
  To: Xavier Leroy; +Cc: micha, caml-list

Big thanks to everyone for this awesome hand-holding with the  
FFI :-). I'm learning, albeit slowly. I have one remaining block on  
my road to success, apologies for reposting.

I get undefined symbols when trying to produce an executable using  
the OCaml library with the C wrapper.

gcc foo.c -L_build -lmorpher -o foo
/usr/bin/ld: Undefined symbols:
_caml_atom_table
_caml_code_area_end
_caml_code_area_start
_caml_static_data_end
_caml_static_data_start
collect2: ld returned 1 exit status

nm _build/libmorpher.a |grep caml_atom_table
00000400 C _caml_atom_table
          U _caml_atom_table

What am I doing wrong?

	Thanks, Joel

--
http://wagerlabs.com/






^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Caml-list] Wrapping OCaml function returning a variant
  2007-03-28 15:07           ` Joel Reymont
@ 2007-03-28 22:47             ` Joel Reymont
  0 siblings, 0 replies; 16+ messages in thread
From: Joel Reymont @ 2007-03-28 22:47 UTC (permalink / raw)
  To: Joel Reymont; +Cc: Xavier Leroy, micha, caml-list

I wasn't calling caml_startup in my code.

The errors went away once I did.

Foot in mouth!

On Mar 28, 2007, at 4:07 PM, Joel Reymont wrote:

> Big thanks to everyone for this awesome hand-holding with the  
> FFI :-). I'm learning, albeit slowly. I have one remaining block on  
> my road to success, apologies for reposting.
>
> I get undefined symbols when trying to produce an executable using  
> the OCaml library with the C wrapper.
>
> gcc foo.c -L_build -lmorpher -o foo
> /usr/bin/ld: Undefined symbols:
> _caml_atom_table
> _caml_code_area_end
> _caml_code_area_start
> _caml_static_data_end
> _caml_static_data_start
> collect2: ld returned 1 exit status

--
http://wagerlabs.com/






^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2007-03-28 22:47 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-03-28 11:33 Wrapping OCaml function returning a variant Joel Reymont
2007-03-28 11:47 ` [Caml-list] " Richard Jones
2007-03-28 12:25 ` micha
2007-03-28 12:51   ` Joel Reymont
2007-03-28 13:28     ` Richard Jones
2007-03-28 14:34     ` micha
2007-03-28 14:46       ` Joel Reymont
2007-03-28 14:56         ` micha
2007-03-28 14:57         ` Xavier Leroy
2007-03-28 15:07           ` Joel Reymont
2007-03-28 22:47             ` Joel Reymont
2007-03-28 12:55 ` Serge Aleynikov
2007-03-28 12:01   ` Joel Reymont
2007-03-28 13:40     ` Serge Aleynikov
2007-03-28 12:13   ` Joel Reymont
2007-03-28 13:53     ` Serge Aleynikov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).