Thoughts on expression matching in JavaScript
Tags: javascript, erlang
Published: 2021-05-04 17:00:35

## Context
Just one word - curiosity. It stays with me through the whole learning process of programming.

When I met Erlang's built-in mechanism of expression matching I couldn't stay inert and immediately started comparing it to what I know in JavaScript.

## What does JavaScript offer
Let's consider these examples when it comes to matching some expressions.

### Example 1 - if
What are we doing here is we describe how our expected value should look like, not to provide something to match.

For me, it also lacks readability because conditions are mostly used to express the logic and perform various value checks, not to directly deal with the data.

```js
const response = {data: 'foo'};
if (response === true) {}
else if (response === 1) {}
else if (response.data === 'foo') {}
else if (conditionN) {}
// ...
else {}
```

### Example 2 - switch/true
Similar to the conditions listed above we still describe the value we want to match.
However, for me, it is more readable.

```js
const response = {data: 'foo'};
switch(true) {
  case response === 1: break;
  case response.data === 'foo': break;
  case conditionN: break;
  // ...
  case true: break;
}
```

### Example 3 - switch
Here, things start to get more interesting.

```js
const response = {data: 'foo'};
switch(response) {
  case {data: 'foo'}:
    console.log('matched!');
    break;
}
```

This *won't work* because of the way JavaScript compares the values.
I don't want to list all scenarios below, but you can [learn more here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is).
```js
{data: 'foo'} === {data: 'foo'} // false
{data: 'foo'} == {data: 'foo'} // false
Object.is({data: 'foo'}, {data: 'foo'}) // false
Object.is(response, response) // true
```

### Example 4 - RegExp
Let's give it a try. It's the closest solution I can think of in terms of expression matching.

```js
const response = {data: "foo"};
/^{"data":(.+)}$/.exec(JSON.stringify(response)); // ["{"data":"foo"}", ""foo"", ...
```

It's nice but has some cons. How about a tailored solution?

## What does Erlang offer?
Let's just have a look at this code.

```erlang
Response = {{data, "foo"}}.
case Response of
  {{data, "foo"}} -> io:fwrite("matched!");
  {{data, Data}} -> io:fwrite("matched ~p!", [Data]);
  1 -> io:fwrite("1");
  _ -> io:fwrite("default match")
end.
% matched!
```

We don't even know some values in the match expression but Erlang is still able to find them.

## Experimenting with JavaScript implementation
After a couple of days where I couldn't write anything worth sharing, I have some POC, that you can find [here](https://github.com/kraftdorian/js-expr-poc).

```js
const response = {
  status: false,
  message: "Error",
  some_dynamic_key: null
};
const template = {
  status: "<<expr@Status>>",
  message: "<<expr@Message>>",
  ["<<expr@DynamicKey>>"]: "<<expr@DynamicKeyValue>>"
};
const result = match_val(response, template);

console.log(result); // [true, [false, 'Error', 'some_dynamic_key', null]]
```

## Summary
Overall, I think that an expression matching mechanism in JavaScript would be nice to have for specific use-cases as we have in functional programming.

Also, it's always nice to learn new things and how they could have been implemented.

###### Article cover photo by [Michael Dziedzic](https://unsplash.com/photos/gEN5Btvf2Eg)