The third parameter: bs-webapi and documentation


#1

While learning ReasonML and bs-webapi, I had a hard time understanding how to use a function in the bs-webapi library. Since there is no documentation, I thought I could look at the code, but here I found something confusing.

Example:

Webapi.Dom.EventTarget.addEventListener(
  "click",
  someClickHandler,
  Webapi.Dom.Element.asEventTarget(element)
) 

This takes three parameters, but looking at the library function

[@bs.send.pipe : T.t] external addEventListener : (string, Dom.event => unit) => unit = "";

I can only see two parameters.

I understand that in JavaScript the object is bound like a method, i.e. target.addEventListener(), and in ReasonML it’s part of the parameters, i.e. addEventListener(…, …, target), but where does this happen and how will I understand this from just reading the code?


#2

I think the answer lies here https://github.com/glennsl/bucklescript-ffi-cheatsheet and here https://reasonml.github.io/docs/en/interop.


#3

The @bs.send.pipe indicates that a value of type T.t (the object) is added as the last parameter.

This example from the documentation (originally in OCaml, but translated to ReasonML):

[@bs.send.pipe: array('a)] external map: ((. 'a) => 'b) => array('b) = "";

made it slightly clearer for me. In JS, you would say arr.map(f); in ReasonML you would say map(f, arr). The declaration shows the function (. 'a) => 'b as the first parameter, and the array('a) is inserted as the second parameter via @bs.send.pipe


#4

Yes, I understand that you need some prior knowledge how send.pipe works. It’s still not clear what types you can use when all it says is T.t (in the Webapi example above). Is this any type or do you need to look up the “types” - i.e. the objects - used in plain JavaScript? Without examples, this is not trivial for someone learning the language.


#5

T.t is the type t in the module T. Htere’s nothing particularly magic about that, but the module name might seem unusually short. That is because it is passed in as a functor parameter:

module Impl = (T: {type t;}) => {
 ...
}

The functor, Impl, is instantiated at the bottom of the file where the type of T.t. is specified as Dom.eventTarget:

include Impl({ type nonrec t = Dom.eventTarget; });

I wouldn’t recommend using bs-webapi to learn the language, or when learning the basics of the language. Some of the techniques used are not very beginner-friendly. But when you are ready to venture into more advanced territory there’s a few neat tricks to learn there.


#6

Thanks, that also helped with the information about the functor parameter.

The incentive to learn Reason is to move away from the TypeScript, Redux, React and loose functional programming stack to React with a good FP/typed language. Learning just the language is pretty easy (I already have knowledge of Haskell, Elm and Clojure), so what’s left is to understand how to use the libraries.


#7

There’s some explanation for these techniques and the rationale for using them in the Readme.

But you shouldn’t normally need to use much of bs-webapi. It was never really intended to be used directly by most people, but rather just a solid foundation to build higher level APIs on.


#8

Ok, like Reason React.