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

Array and list mapping question #82

Closed
monstasat opened this issue Nov 19, 2018 · 3 comments
Closed

Array and list mapping question #82

monstasat opened this issue Nov 19, 2018 · 3 comments

Comments

@monstasat
Copy link

monstasat commented Nov 19, 2018

When mapping a JS array to OCaml array with gen_js_api, a new object is instantiated:

  let n = int_of_js (get objs "length") in
  Array.init (n - start) (fun i -> f (array_get objs (start + i)))

A new object is also created when mapping OCaml array to JS:

let array_make n = new_obj (get global "Array") [|int_to_js n|]

let array_to_js f arr =
  let n = Array.length arr in
  let a = array_make n in
  for i = 0 to n - 1 do
    array_set a i (f arr.(i))
  done;
  a

I want to map a JS object (which has fields of type 'array') to OCaml:

module Dataset : sig
   (* JS object *)
    type t
   
    val data : t -> float array
    val set_data : t -> float array -> unit

   (* Some other bindings here *)

    val make : ?data:float array ->
               (* Some other bindings here *)
               unit ->
               t [@@js.builder]

Javascript object t is used by an external JS library to render data on a chart. When the data array is mutated, the chart is re-rendered.
The problem here is that when I do such a mapping, a new data array is created, and all changes are made with a new object, not the original one. Original array stay untouched. Mutating this new array causes no re-render of a chart because it is not a part of t object. To force re-render, I should not only mutate the new array, but also set this new array to t object via set data function. This seems like a great overhead.
What is the best way to handle this problem?
Is there any way to make "direct" mapping between JS and OCaml arrays without new allocations?

@nojb
Copy link
Member

nojb commented Nov 22, 2018

Did you consider binding a function

val set: t -> int -> float -> unit
[@@js.implem let set a i x = Ojs.array_set (Ojs.get a "data") i (Ojs.float_to_js x)]

?

@monstasat monstasat reopened this Nov 23, 2018
@monstasat
Copy link
Author

monstasat commented Nov 23, 2018

I came to a similar solution. The only problem is that type t is not polymorphic, so I need to use a functor to use it with different types. Maybe the bindings can be implemented with 'a t type? Can this be done with gen_js_api? E.g. to have a 'set' function with the following interface:

val set: 'a t -> int -> 'a -> unit

?

@nojb
Copy link
Member

nojb commented Nov 23, 2018

A simple-minded approach is just to take Ojs.t arguments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants