Hologram Elixir -> JS compilation

Your observations are correct! Elixir modules get compiled by Hologram, but calls to underlying Erlang modules need the corresponding Erlang functions to be manually ported to JavaScript.

Help on porting :sets module functions is definitely welcome! You can find the manually ported Erlang functions here: https://github.com/bartblast/hologram/tree/dev/assets/js/erlang
These functions are relatively straightforward to port, and I’d be happy to review pull requests. Just please create separate pull requests for each function so I can review them quickly.

Let me walk you through the procedure using :lists.keymember/3 as an example (from lists.mjs):

Structure of manually ported functions:

Each function follows this pattern:

// Start keymember/3
"keymember/3": (value, index, tuples) => {
  return Type.boolean(
    Type.isTuple(Erlang_Lists["keyfind/3"](value, index, tuples)),
  );
},
// End keymember/3
// Deps: [:lists.keyfind/3]

Key components:

  1. Start/End comments: These allow the Hologram compiler to extract the source code during compilation
  2. Deps comment: Lists dependencies on other Erlang functions. This information is currently duplicated in Hologram.Compiler.CallGraph module’s @erlang_mfa_edges attribute, but eventually there will be only one source of this information.

What you’ll typically need:

  • Type class: Provides boxed type utilities (Type.boolean(), Type.isTuple(), etc.)
  • Interpreter class: For function calls, error handling, and comparisons
  • Bitstring class: For binary operations (if needed)

Critical requirements for implementation:

  1. OTP Consistency: Make sure your functions are consistent with the actual OTP implementation. Check the function documentation in iex:

    iex> h :lists.keymember/3
    

    And refer to the official Erlang documentation: e.g. https://www.erlang.org/docs/26/man/lists

  2. Testing Requirements: Each function must have two types of tests:

Important guidelines:

  • Never mutate the parameters - return new values, or return parameters unchanged
  • Follow the existing validation patterns (you’ll notice some duplication in parameter validation, but don’t worry about DRY-ing it up - just follow current conventions for now)
  • Use the same error handling patterns as existing functions
  • Test thoroughly against the OTP behavior to ensure consistency

For :sets module functions, you’ll want to look at how similar data structure operations are implemented in the existing maps.mjs and lists.mjs files.

Feel free to start with any :sets function you need and create a PR - I’m here to help with any questions during the implementation! :slight_smile:

1 Like