I thought multiplication was going to be easy
Tags: elm, webdev
Published: 2019-07-09 12:52:29

---
title: I thought multiplication was going to be easy
published: true
description: 
tags: elm, webdev
---

After adding addition and subtraction to my calculator I decided to proceed with multiplication.

Due to good [separation of concerns](https://dev.to/dwayne/separating-application-logic-from-the-ui-in-elm-8nj) it required little change to the [code](https://github.com/dwayne/elm-calculator/commit/848c4e35d9cb0d5ea0140b283beff5b3e77cdd1e). However, that wasn't going to be the end of it.

After using the calculator for a while I stumbled upon the expression `1+2*3`.

![Incorrect answer due to ignoring operator precedence](https://thepracticaldev.s3.amazonaws.com/i/5n8nbg1fqu6htn2xv52f.png)

`1+2*3=1+6=7` but my calculator gave `9` because it did `1+2*3=3*3=9`. I forgot that my [expression evaluator](https://github.com/dwayne/elm-calculator/blob/848c4e35d9cb0d5ea0140b283beff5b3e77cdd1e/src/Calculator.elm#L130) didn't handle operator precedence.

## A good opportunity to add a test

I knew improving my expression evaluator would require a non-trivial code change and I knew that I didn't want to be constantly entering expressions via the UI to check if I correctly implemented the evaluator.

So I added [a failing test](https://github.com/dwayne/elm-calculator/blob/848c4e35d9cb0d5ea0140b283beff5b3e77cdd1e/tests/Test/Calculator.elm#L192).

```elm
operatorPrecedenceSuite : Test
operatorPrecedenceSuite =
  describe "operator precedence" <|
    [ test "multiplication is done before addition" <|
        \_ ->
          let
            calculator =
              Calculator.new
                |> Calculator.process (Digit 1)
                |> Calculator.process (Operator Plus)
                |> Calculator.process (Digit 2)
                |> Calculator.process (Operator Times)
                |> Calculator.process (Digit 3)
                |> Calculator.process Equal
          in
            calculator
              |> Calculator.toDisplay
              |> Expect.equal { expr = "1+2*3=7", output = "7" }
]
```

## The shunting yard algorithm

I just implemented enough of the [shunting yard algorithm](https://en.wikipedia.org/wiki/Shunting-yard_algorithm) to get addition, subtraction and multiplication working correctly. With plans to add division in the near future.

![Correct answer](https://thepracticaldev.s3.amazonaws.com/i/dmed429o82gvpz9s86r4.png)

Here's the [code](https://github.com/dwayne/elm-calculator/blob/0c1f708e1983b1afb75f023fd7ff190fea6587fd/src/Expr.elm#L15) if you're interested in the implementation details.

The `operatorPrecedenceSuite` test passed and I was elated.

## Elm handled the complexity well

Initially the expression evaluator was hidden inside the `Calculator` module. But the complexity of the evaluator got to the point where I wanted to ensure it was correct without having to go through the `Calculator`'s public API.

To handle the complexity I factored the evaluator into its own module, [Expr](https://github.com/dwayne/elm-calculator/blob/0c1f708e1983b1afb75f023fd7ff190fea6587fd/src/Expr.elm), with the following public API:

```elm
module Expr exposing (Expr(..), eval, toString)
```

This allowed me to extensively test it. For e.g. here's one of the tests I added:


```elm
test "1+2*3" <|
  \_ ->
    Expr.eval (Add (Const 1) (Mul (Const 2) (Const 3)))
      |> Expect.equal 7
```

You can view the full suite of tests [here](https://github.com/dwayne/elm-calculator/blob/0c1f708e1983b1afb75f023fd7ff190fea6587fd/tests/Test/Expr.elm).

## It was simple

Even though I ended up writing a lot of extra code I still felt that Elm managed the complexity well. I still understand how my code works, I know where I need to make changes when I need to add a new feature and the types along with the tests make me feel extremely confident in my implementation.

Though adding multiplication to the calculator wasn't easy. Elm made it [simple](https://www.infoq.com/presentations/Simple-Made-Easy/).