Where Did All My Methods Go? Modules in ReasonML
Tags: javascript, reason
Published: 2019-06-30 18:22:50

Coming from JavaScript to ReasonML there are a lot of barriers. While the syntax may look friendly at first, and the type inference is amazing requiring very little effort from you to massage it, there are a lot of symbols, and a huge mental shift needs to take place.

To help others coming from non-functional languages, and JavaScript
specifically, I want to start sharing some of the things that tripped me up when I was learning ReasonML.

The community is one of the best around and someone will always help you no matter how silly you think your question is, but there isn't a ton of content surrounding ReasonML online. Join the [discord](https://discord.gg/reasonml), and don't be afraid to post on the [forum](https://reasonml.chat).

---

Functional programming languages tend to structure their code differently than non-functional languages. Whether or not you consider JavaScript to be an object oriented language, it still has some form of inheritance using the prototype chain, and you call methods directly on the instance of the data structure.

## The JavaScript Way

An example. In JavaScript you can create an array literal like so:

```javascript
const myFriends = ["Me", "Myself", "I"];
```

And you can use the Array methods by using the dot notation on the instance of the data structure.

```javascript
const myFriends = ["Me", "Myself", "I"];

const shoutingFriends = myFriends.map(friend => friend.toUpperCase());
```

### Under the Hood

In JavaScript when you declare a new array literal you are creating a new instance of the Array pseudo-class.

```javascript
const myFriends = new Array("Me", "Myself", "I");
```

A naive implementation of an Array in JavaScript using pseudo-classes might look like this:
```javascript
function MyArray() {
  // pretend I didn't use an actual Array in my definition
  this.value = Array.from(arguments)
  this.length = arguments.length
}

MyArray.prototype.forEach = function(cb) {
  for (let i = 0; i < this.value.length; i++) {
    cb(this.value[i], i, this.value);
  }  
}

MyArray.prototype.map = function(cb) {
  let __internal = [];

  this.forEach(function(element, index, array) {
    __internal.push(cb(element, index, array));
  });

  return __internal;
}

const myFriends = new MyArray("Me", "Myself", "I");
const shoutingFriends = myFriends.map(friend => friend.toUpperCase());

```
>You might be used to seeing classes instead of pseudo-classes, but under the hood JavaScript classes are just syntatic sugar that results in the same thing.

Important to note that our methods have an *implicit* dependency on `this` (the instance itself). We aren't passing an array into the method. The *implicit* dependency on `this` is what allows the dot notation `myFriends.map...`.

Our instance of `MyArray` doesn't actually copy over `forEach`, or `map` because that would be extremely inefficient. If our program has tens-of-thousands of arrays it would be unnecessary to copy EVERY method to each instance of the data structure. Instead JavaScript has this thing called the prototype.

So when we use `myFriends.map...` the engine goes "Hmmm.... 🤔 myFriends doesn't seem to have a function called `map` on its prototype. Perhaps its proto does." and then it checks `MyArray`, because when we create an instance of a (pseudo-)class JavaScript adds some information to our instance so later it knows who to inherit functions from.

Then it sees that "Ahhh. Yes! `MyArray` does a have function on its prototype called `map`", and then it uses that `map` function for our operation.

All of this rambling is to show you how data structures and methods are
tightly coupled in JavaScript. To map an array we use the instance of the array, and chain a function onto it like so `[1,2,3].map(n => n + 1)`.

When you learn this as the norm, you think, "Well yeah, duh. How else would you do it?". 

---

## The ReasonML Way

In functional programming languages data structures store data. That's it. How do you do operate on data structures then? In ReasonML we place collections of functions that operate on a type into Modules. A module might know how to operate on one type only, like an Array for example. 

The functions have an *explicit* dependency of an Array.

In ReasonML the `Array` module contains *most* functions that know how to operate on the array data structure. What are the benefits of modules? They're self-contained. They don't have to be copied or have pointers created to their 'owners'. They also avoid notions of 'this/self' or the instance of the data structure at all.

They are pure functions that take explicit arguments and return consistent results. 

### An Example

In ReasonML `Array.map` is a function that takes two arguments: 
1. A function that takes whatever the type of data that is contained inside of the array (in the following example it takes a string) and does something to transform each element returning either the same, or a different type (in following example it returns a string).
2. The actual Array we want to operate on.

```ocaml
let myFriends = [| "Me", "Myself", "I" |];
let shoutingFriends = Array.map(friend => String.uppercase(friend), myFriends);
```

This *explicit* need for the Array to be passed in might still seem like an odd choice, especially if you're used to taking advantage of method chaining in JavaScript or other object oriented languages.

```javascript
const myArray = [1, 2, 3, 4, 5, 6];
const res = myArray
  .map(n => n * 3)
  .filter(n => n % 2 === 0)
  .reduce((acc, n) => acc + n, 0);
// => 36
```

However, you can achieve the same thing in ReasonML in a few different ways.

(I am using a List here instead of an Array for reasons we'll explore in another post, but for our purposes squint and pretend it's an array).

```ocaml
let myArray = [1, 2, 3, 4, 5, 6];
let res = myArray
  |> List.map(n => n * 3)
  |> List.filter(n => n mod 2 === 0)
  |> List.fold_left((acc, n) => acc + n, 0);
/* => 36 */
```

Alternatively if you are using Bucklescript you can use Belt.

```ocaml
let myArray = [| 1, 2, 3, 4, 5, 6 |];
let res = myArray
  -> Belt.Array.map(n => n * 3)
  -> Belt.Array.keep(n => n mod 2 === 0)
  -> Belt.Array.reduce((acc, n) => acc + n, 0);
/* => 36 */
```

Or the Js.Array module...
```ocaml
let myArray = [| 1, 2, 3, 4, 5, 6 |];
let res = myArray
  |> Js.Array.map(n => n * 3)
  |> Js.Array.filter(n => n mod 2 === 0)
  |> Js.Array.reduce((acc, n) => acc + n, 0);
/* => 36 */
```

> I don't want to dive into what the `|>` and `->` operators are in this post. Just know that the `|>` and `->` operators, in addition to currying, can help you achieve this same idea of method chaining. You're taking the result from one function and piping it into the next function.

So in ReasonML methods move from being available on the instance of a data structure, to being contained within a dedicated module. This allows them to be pure functions that require you to explicitly pass in the data structure you want to operate on.


---

### Some Additional Info

If you're comfortable reading type signatures, the following links contain the type definitions for the Array and List modules.

[Array module](https://reasonml.github.io/api/Array.html)
[Belt Array module](https://bucklescript.github.io/bucklescript/api/Belt.Array.html)
[List module](https://reasonml.github.io/api/List.html)
[Belt List module](https://bucklescript.github.io/bucklescript/api/Belt.List.html)

---
### What's next?

ReasonML is still evolving so there are often many ways to skin a cat, and there are often good reasons when to choose one over the other.

In future posts I'm going to explore some of the different modules included in the standard library in ReasonML, as well as Belt and how they relate to JavaScript.