1. 38
  1.  

  2. 2

    It’s exciting to see the progress on Gleam! How do you plan to handle the heavily object-oriented nature of DOM code in general? Your examples use Reflect for assignment, but what if I want to call document.addEventListener or mutationObserver.takeRecords()? Or use the built-in Map type?

    1. 1

      I expect we will have quite thick wrappers around DOM APIs that expose a limited subset of what is avalible that offers a stateful functional interface over the DOM’s OOP API. Similar libraries in PureScript and ReScript would be a good place to look for ideas.

      The Map type can be wrapped fairly cleanly, it has quite a small and basic API.

      1. 9

        In my experience, thick wrappers around platform APIs with huge surface areas like the DOM not effective in the long run unless they allow immediate escape hatches to the underlying platform. With strict segmentation or difficult interop, experts in the underlying APIs need to re-learn the facade abstractions you produce, and online learning resources need to be translated in the mind of the developer before they can be applied. Thick wrappers need maintenance to keep up with the platform, which is taxing on an emerging community. That isn’t to say wrappers are pointless, but they are a (in my opinion) very low local maximum unless there’s an easy escape hatch.

        My case study here is React. React is a thick library over UI tree manipulation and state lifecycle. On the web, ReactDOM does great because users who want more can trivially access the underlying platform APIs: getting a DOM node and calling methods directly on it is a one line affair. But on mobile, React Native is extremely isolated from the platform. To call an unwrapped (or poorly wrapped) platform API requires writing platform-native code, serializing messages over a bridge between language runtimes etc. I rewrote Notion’s Android mobile app to remove React Native. I am not planning to rewrite Notion’s web app to remove React. Of course Gleam is not going to be so isolated from the platform — just using it as an extreme example.

        Here’s how ReScript low-level interop looks directly against DOM objects:

        // The type of document is just some random type 'a
        // that we won't bother to specify
        @val external document: 'a = "document"
        
        // call a method
        document["addEventListener"]("mouseup", _event => {
          Js.log("clicked!")
        })
        
        // get a property
        let loc = document["location"]
        
        // set a property
        document["location"]["href"] = "rescript-lang.org"
        

        Does Gleam have a similar less-typed but more direct syntax for building the wrapper libraries?

        It seems that Purescript prefers to write an “externs” header like file, and have the wrapper actually implemented in JS. Looking at the Purescript wrapper for MutationObserver object’s takeRecords method. Here’s the signature

        foreign import takeRecords :: MutationObserver -> Effect (Array MutationRecord)
        

        And the implementation in the adjacent .js file:

        exports.takeRecords = function (mo) {
          return function () {
            return mo.takeRecords();
          };
        };
        

        Between the two approaches, I much prefer ReScript.

        1. 1

          Both are possible in Gleam, you can do whatever you like using the FFI. Pick the approach that fits each use case.

        2. 1

          One of the “newer” Browser API libraries I’ve worked with is https://erratique.ch/software/brr. It’s been a real pleasure to work with in js of oCaml, and the API seems to be very understandable. If you haven’t seen it yet it’s worth a look.

      2. 1

        is the integer type still a big integer in the javascript version?

        1. 1

          No, it uses the JavaScript integer type by adding bitwise hints to their number literals.