Skip to content

object ffi design (taken from #123) #174

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
bobzhang opened this issue Mar 11, 2016 · 8 comments
Closed

object ffi design (taken from #123) #174

bobzhang opened this issue Mar 11, 2016 · 8 comments

Comments

@bobzhang
Copy link
Member

#123 for the object part

@bobzhang bobzhang added this to the future- milestone Mar 11, 2016
@bobzhang
Copy link
Member Author

bobzhang commented Apr 14, 2016

I have some better ideas. now since we introduce _ Js_fn.t, so that we can tell js uncurried function from ocaml curried function by the type, so we can do the same by introducing 'a Js.read and `'a Js.write'

so we only need to know the method dispatching is on js object or ocaml object (previously we also have to encode the arity) for an efficient FFI.

a bit convention would help

proposal one:

x # length (* ocaml object --> compiled in ocaml style *)

x #_length |> Js.read (* js object *)
(* or we can do x#Length *)
class type js_obj = object
   method _length : int Js.read
   method _hey : (int * unit) Js.fn
   method _v : int Js.write
end

(* or *)
class type js_obj = < _length : int Js.read, _hey : (int * unit) Js.fn >

(* run js call *)
let v = Js_fn.run1 x #_hey 3 (* Js_fn.run1 will do the magic !! *)
(* compiled as  x.hey(3)*)

(* js set *)
x #_v |> Js.write 3 (* compiled as x.v =  3 *)

note that js_of_ocaml use x ## length which is a syntax exntension and lift the type into phantom types, here x#_length is no more complex than x##length but it is vanilla ocaml (no complex syntax extension and complex types!)

Having ocaml style structural typing available for FFI would be a really exciting feature, @copy what do you think?

@copy
Copy link
Contributor

copy commented Apr 15, 2016

Having ocaml style structural typing available for FFI would be a really exciting feature, @copy what do you think?

I like the idea. The syntax for properties is a bit verbose, but I guess we can still provide a ppx extension to rewrite it. JSOO uses this syntax: http://ocsigen.org/js_of_ocaml/2.7/api/Ppx_js. It would be great if bucklescript was compatible with this syntax. Are phantom types necessary for that (for example to handle a read-only property and a read-write property similarly)?

Is the underscore necessary? Wouldn't this work too: class type js_obj = object method length : int Js.read end.

What happens when a property (something of type t Js.read) escapes? For example let v = x#_v in Js.write v 3.

@bobzhang
Copy link
Member Author

bobzhang commented Apr 15, 2016

think twice, I think Js.read Js.write is not necessary, we can use _set_property
so it would be like

class type v = 
  object
    method _length : int 
    method _set_length : int -> unit 
    method _a_fun : (int * int * int ) Js_fn.t (* int -> int -> int *)
  end 

there is another proposal

type + 'a t 
external (!) : 'a t -> 'a = "down_to_normal_object"

let f x = 
   !x # length + !x # width
(* compiler would infer *)
val f : <length : int , width : int, .. >  t ->  int 

There are escape issues as well, when we found code like below, we raise an error
(another minor issue, (!) is already used, there seems no other operator available, and
the type is lifted, there are some complexities here)

let f x = 
   let  v = !x in v # length + v # width

we try to avoid the complexity of js_of_ocaml syntax extension, its rewrites rules are too complex

@bobzhang
Copy link
Member Author

bobzhang commented Apr 15, 2016

again, I think the optimizer can easily handle this case as long as the unwrapped js object is not crossing function boundary

let f x = x # length + x # width
let () = f !x 
 (* wrong -- compiler error  [!x] is not immediately dispatched -- 
    considering [f] is not inlined -- however, f can be inlined, in 
    that case this will be valid code, this is sound still , but it is a bit
   magical *)

let f x = 
  let v = !x in 
  v # length + v # width (* fine *)

note this seems better, however, it is not deterministic, since sometimes optimizer would do aggressive work, the escaped-case will turn into non-escaped case (valid code), is
this a big issue, @copy ?

@copy
Copy link
Contributor

copy commented Apr 15, 2016

think twice, I think Js.read Js.write is not necessary, we can use _set_property so it would be like

That's better.

again, I think the optimizer can easily handle this case as long as the unwrapped js object is not crossing function boundary

It's not too bad, it's just a weird edge case. I like the _set_property version more, using an infix operator is awkward. It could also be a subtle source of bugs: If the object escapes (which depends on optimisations, so it shouldn't be relied upon), there's no error and JS and OCaml behaviour is mixed. Actually, couldn't OCaml objects be represented the same way as JS objects (with the exception of methods)?

we try to avoid the complexity of js_of_ocaml syntax extension, its rewrites rules are too complex

So, is it not possible to use a custom syntax? JSOO has obj##.length and obj##.width := 123, which would be nice.

@bobzhang
Copy link
Member Author

If the object escapes (which depends on optimisations, so it shouldn't be relied upon), there's no error and JS and OCaml behaviour is mixed.

No, there is never bug, if escaped, we will get a compile time error in the right location. if you always call a method after !, you will never get such compile time error

let f x = 
  !x # method_call x ; 
  !x # method_call y ;
  !x # property;
  !x # set_property v 

We might introduce a syntax extension, however, it should be okay to use without syntax extension

@copy
Copy link
Contributor

copy commented Apr 16, 2016

No, there is never bug, if escaped, we will get a compile time error in the right location. if you always call a method after !, you will never get such compile time error

Cool, I didn't think it was possible.

@bobzhang
Copy link
Member Author

I think we are almost there, the only remaining piece is to model this semantics

EduardoRFS pushed a commit to EduardoRFS/bucklescript that referenced this issue Mar 11, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants