Skip to content
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

ffi (calling js from ocaml) #101

Closed
bobzhang opened this issue Feb 17, 2016 · 15 comments
Closed

ffi (calling js from ocaml) #101

bobzhang opened this issue Feb 17, 2016 · 15 comments

Comments

@bobzhang
Copy link
Member

note that call ocaml from js is very easy, and there is not much work to do. (see the runtime representation #24), we also plan to use some ppx_derivings to hide the internal representation.

calling js from ocaml is a bit hard, since you have to write type declarations, for binding simple functions

external array_map : 'a array -> ('a -> 'b) -> 'b array = "" [@@js.call "Array.prototype.map.call"]

for binding js objects we can do this

class type dom = object
   method getElementById : string -> node
end
external document : dom = ""[@@js.global "document"]

let f v = document#getElementById v

To make it more efficient user can write bindings

class type dom = object
   method getElementById : string -> node
   method getElementById_js_01 : string -> node
   method properties_js_set : string -> node
end
external document : dom = ""[@@js.global "document"]

let f v = document#getElementById_js_01 v 

Note that document#getElementById_js_01 and document#getElementByID compiles to js code which behaves exactly except that the former will be as efficient as handwritten js code

@bobzhang
Copy link
Member Author

@jordwalke what do you think?

@alainfrisch
Copy link

What about combining efforts so that the same binding specification can be used through bucklescript and through js_of_ocaml. gen_js_api ( https://github.com/LexiFi/gen_js_api ) was designed to be rather independant of "how OCaml is compiled to JS", and it could serve as a good basis for discussion. I don't see immediately any problem to have gen_js_api support two variants of its code generation to support both js_of_ocaml and buckescript. It would be great to be able to write OCaml projects than can be compiled with any of the 2 compilers, without having to do the glue with JS libraries twice.

@bobzhang
Copy link
Member Author

@alainfrisch I am not very clear how js_of_ocaml ffi really works (cc @hhugo), from the user's point of view, I think js_of_ocaml ffi is a bit complicated (require non-trival ppx ) and the type signature is hard to read even for experienced ocaml programmers. Here we want to use js object just as normal ocaml objects, but you can not inherit it.

If I understand correctly, gen_js_api does not use ocaml objects, so as long as js_of_ocaml and bucklescript use the same runtime representation, it should be good, right? (technically, I think they can share the same runtime encoding)

@alainfrisch
Copy link

I think the core question is how to specify how JS components are reflected in OCaml, i.e. the design of the FFI specification. It's not so much a question of runtime representation; except for the Ojs module, gen_js_api itself does not know how js_of_ocaml represents OCaml values. Btw, gen_js_api is independant of js_of_ocaml "native FFI" (which is tightly coupled to the way js_of_ocaml represents OCaml values in JS).

@bobzhang
Copy link
Member Author

@alainfrisch maybe we can formalize how to use js attributes? for js_of_ocaml user, they can run the gen_js_api, for bucklescript, user just run the compiler, is this what you mean?

note that we can refer other js api in module style

external f : int -> int = "" 
  [@@js.call "ffi_from_js"]
  [@@js.module  "file_name.js" "the_opt_js_module_name"]

@fxfactorial, based on your experience of writing bindings to ocaml-nodejs, does this fit your purpose?

@fxfactorial
Copy link

yes, that would be very nice. What would JS constructors look like?

@copy
Copy link
Contributor

copy commented Feb 18, 2016

What's the difference between document#getElementById_js_01 and document#getElementByID? Is it related to the number of arguments? This looks really ugly to me, couldn't it be done with another annotation?

@bobzhang
Copy link
Member Author

@copy document#getElementById_js_01 will be the same as document#getElementById except that it will be more performant, since it also conveys to the compiler that it is a js method and arity is 1, so we can do this in compile time instead of delaying to runtime. It's optional to write more performant code.(if you dont care about performance, just write document#getElementById
There are some technical challenges to get attributes for non-external functions.

@fxfactorial
we will have a attribute like below

external new_obj : arg_type -> obj_type = "" [@@js.new "js_constructor_name"]

@fxfactorial
Copy link

@bobzhang and subclassing? Say like Node's streaming duplex, they were a little challenging for me to play with type system. What is the empty string, some minimal hack needed to satisfy the syntax of external declarations?

EDIT: nvm, looks like you can't subclass yet, just saw that above.

@alainfrisch
Copy link

@alainfrisch maybe we can formalize how to use js attributes? for js_of_ocaml user, they can run the gen_js_api, for bucklescript, user just run the compiler, is this what you mean?

The core principle of gen_js_api is to derive implementation of glue code (.ml files) from plain OCaml interfaces (.mli files) annotated with custom js attributes (to specify how the binding is done). The generated glue code depends on a runtime support library (Ojs) which encapsulates the knowledge on how to interact with Javascript from OCaml. No assumption is made by the tool itself on the encoding of OCaml values in JS.

The version of Ojs shipped with gen_js_api is built on top of primitives provided by js_of_ocaml's runtime (it does not use any of the OCaml libraries from js_of_ocaml's stdlib). It would be interesting to see how far one can go by simply providing an implementation of Ojs for bucklescript.

@alainfrisch
Copy link

Here is the interface of Ojs:

https://github.com/LexiFi/gen_js_api/blob/master/ojs.mli

Do you think it could be implemented for bucklescript?

@bobzhang
Copy link
Member Author

@alainfrisch Have a cursory look of the interface, I think it should be fine, I will look into more details about the design of gen_js_api

@bobzhang
Copy link
Member Author

For the record, we can do the same thing with ocaml object (for better performance when needed), method_name__ml_01. This is trivial to do in generated code, for example, the visitor pattern is generated from a type definition, this will help boost the compiler performance when bootstrapping our compiler in the future

@bobzhang
Copy link
Member Author

we can introduce a ppx extension for type definition

class type dom = object%js
   method getElementById : name -> x
end

will generate

class type dom = object
  method getElementById : name -> x 
  method getElementById__js_01 : name -> x 
end

@bobzhang
Copy link
Member Author

see #174

EduardoRFS pushed a commit to EduardoRFS/bucklescript that referenced this issue Apr 5, 2021
kevinbarabash pushed a commit to kevinbarabash/rescript-compiler that referenced this issue Dec 24, 2021
…ng#101)

When a comma is missing between nodes in a region and the current token looks like the start of something valid in the current region, we should report an error with regards to the missing comma.

Example:
  type student<'extraInfo> = {
    name: string,
    age: int
    otherInfo: 'extraInfo
  }
There is a missing comma between `int` and `otherInfo`.
`otherInfo` looks like a valid start of the record declaration.
We report the error here and then continue parsing the region.

Fixes rescript-lang/syntax#100
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

4 participants