How do you writing bindings today?

Hi there,

Recently, I have been asking myself how others deal with bindings.
Since BuckleScript, bindings of API like this :

const someLib = {
  exec: () => 4
}
someLib.exec()

are written in OCaml style with module t like this with @send :

module SomeLib = {
  type t

  @module("xx")
  external instance: t = "default"
  @send
  external exec: (t, unit) => int = "exec"
}

SomeLib.instance->SomeLib.exec()

But today we can write JS like bindings like this :

type lib = {
  exec: unit => int
}

@module("xx")
external myLib: lib = "default"

myLib.exec()

The JavaScript output will be the same with no cost but the usage feels pretty different. Should we enforce more a pattern than another ? :thinking:

I would say: use the form you prefer.
I would write my bindings in the second form (SomeLib.instance->SomeLib.exec()), so it is more idiomatic (compare rescript/core, std lib, etc.)

For the specific case I’d write it this way:

module SomeLib = {
  @module("xx") @scope("default")
  external exec: unit => int = "exec"
}

SomeLib.exec()
1 Like

I don’t recommend the options, because when there’s a function overload on js side you want to bind to multiple functions like:

module SomeLib = {
  @module("xx") @scope("default")
  external execString: string => int = "exec"

  @module("xx") @scope("default")
  external execInt: int => int = "exec"
}

SomeLib.execString()
1 Like

Yes for this case, I tend to use this kind of declaration.
But as the goal is to be as close as possible to JavaScript, I think the second option can be relevant (when the API allows it)

I do both. no problem there

OCaml style modeling is still useful, so I won’t abandon it