ReScript and Classless Coding
Tags: rescript, javascript, class, functional
Published: 2021-06-21 19:40:50

ReScript is one of my favorite languages right now. It's an easy-to-grasp functional-first language that transpiles to javascript. Unlike some other transpile-to-js languages, you don't need a jvm / .net runtime to get going. In fact it's faster than typescript to get going...

https://rescript-lang.org/docs/manual/latest/installation

It's syntax is essentially a subset of javascript with functional elements carefully crafted into it.

Not only is it easy to use, it makes code far far more predictable and safe.

ReScript however, doesn't have or need classes / prototypes.

In this post I want to show you how you can easily work in this classless paradigm.

## Separate state from function

Firstly it helps to separate the concept of state from function.

In our example, we're going to create an instance of a person. This is done with a `type` and a `let`.

```rescript

type person = {
  name: string,
  age: int
}

let bob = {
  name: "Bob",
  age: 28
}

```

In the above, since there is a type that matches bob's signature, bob's type is inferred to be person. We could have declared bob explicitly with `let bob: person = { ... }`.

Now that we have our state, we can think about function(s)...

## Group functions into modules

It's common to group functions that work on the same type of data into a common module. This is somewhat similar to methods within a class. In the below module we have a `greet` and a `tellAge` function. 

Again, note that we haven't had to tell the functions that `thisPerson` is of type `person` because it is able to infer this.

```rescript

module Person = {
  let greet = thisPerson => {
    thisPerson.name
      ->x => { x ++ " says Hello." }
      ->Js.log
    thisPerson
  }

  let tellAge = (thisPerson) => {
    open Belt.Int
    thisPerson
      ->x => { x.name ++ " is " ++ x.age->toString ++ " years old" }
      ->Js.log
    thisPerson
  }

}

```

In ReScript you will often see the `->` operator which allows you to "pipe" the previous value into the following function. For example `10->increment->increment` is the same as `increment(increment(10))`.

ReScript doesn't use the `return` keyword, but rather returns the last expression in the function. Both of our functions return `thisPerson`.

## Putting it together

So now we "pipe" bob into one of the functions... let's say `greet`.

```rescript

// Note: In ReScript, a top-level expression must always be `unit`. 
// `unit` is very similar to `undefined` is javascript.
// Since `bob->Person.greet` returns a type of `person` we use `ignore` to ignore this type and just return `unit` instead.

bob->Person.greet->ignore 

```

Since `Person.greet` returns back `bob`, we can then continue to pipe into other `Person` functions...

```rescript

// Using open allows us to drop the need to write `Person.greet` and `Person.tellAge` and just use `greet` and `tellAge`

open Person 

bob
  ->greet
  ->tellAge
  ->ignore

```

Note how we can use the `->` a bit like method chaining in OOP.

One cool thing with this style of syntax is that `bob` doesn't have to be piped into a function from the `Person` module and in fact can be piped into any function that accepts the signature.

For example, lets create a standalone function called `incrementAge`...

```rescript

let incrementAge = thisPerson => {
  name: thisPerson.name,
  age: thisPerson.age + 1
}

open Person

bob->incrementAge->greet->tellAge->ignore

```

Now when we run the program it prints:

```

Bob says Hello.
Bob is 29 years old

```

## Immutable-first

You may have noticed that `incrementAge` did not mutate `bob`, but rather immutably produced a new version of `bob` to continue passing through the pipe. This illustrates an important part of functional programming, in that where ever possible, the best approach is to use pure functions like this, that don't mutate existing values. We could then for example keep a current version of `bob` and `bob1YearFromNow`...

```rescript

let bob1YearFromNow = bob->incrementAge

bob->greet->tellAge->ignore

bob1YearFromNow->greet->tellAge->ignore

```

## Mutating Props

A good 90+ % of our code should be immutable, but what about when we just want to emulate a class and mutate some props! We can do that like so...

Firstly the `person` type will need to explicitly call out that a particular property is mutable (Since everything is immutable by default). From there, we can create a function that accepts a `person` and mutate the `age` property. Again, we pass back `thisPerson`, so that piping can continue should it need to.

```rescript

// Updating person to have a mutable age
type person = {
  name: string,
  mutable age: int
}

let jill = {
  name: "Jill",
  age: 26
}

let mutIncrementAge = thisPerson => {
  thisPerson.age = thisPerson.age + 1
  thisPerson
}

jill->mutIncrementAge->ignore

```

## Conclusion

So now we have seen how it's possible to emulate class-like behavior in ReScript, however when it comes to mutation - you will rarely see the mutation of single props like above. Mutation usually happens as immutably as possible in a functional-first language. That however sounds like a **part 2**.

Have you used ReScript?
How do you use a classless language?

Thanks all :)