DEV Community

leojpod
leojpod

Posted on • Originally published at Medium on

6 1

Why is there no need for Multicase matching in Elm

As a beginner developer with Elm, I quickly ended up both loving the union types and the _ operator but founded a tad bit irritating the absence of Multicase matching until … Until I saw the light!

TL;DR?

Use the following pattern whenever you have some behaviour shared by several constructor of your union types and stay away from the _ operator!

type alias Props = { start: Date, stop: Date, assignee: String}
type Item
= Task Props
| SubTask Props
| Bug Props
| Epic Props
| ...
assignTo: String -> Item -> Item
assignTo person item =
let
changeAssignee props = {props | assignee = person}
in
case item of
Task p -> Task (changeAssignee p)
SubTask p -> SubTask (changeAssigne p)
...
view raw letin.elm hosted with ❤ by GitHub

The problem with single case matching

Let's say I want to create a task tracking software. I might end up with this Item type to describe my model:

type Item
= Task Props
| SubTask Props
| Bug Props
| Epic Props
| ...
view raw item.elm hosted with ❤ by GitHub

As you can guess, a lot of operations are gonna require the same treatment for most kind of Item : assigning the item to somebody, changing the start or end date, adding/editing a description, … while there will be some that will differ. So how can we deal with that?

Using the underscore matching

When I encountered this problem my first idea was to use the _ to match all the kind of Item that didn't require a specific treatment for any given case ... of . There are two main problems with that approach: we can't get the properties and it introduce potential BUGS! And by that I mean problems and unexpected behaviour that won't be caught up by the compiler. But first let's see how it looks:

-- make some treatment on the tasks
toString: Item -> String
toString person item =
case item of
Task p -> ("task assigned to " ++ p.assignee)
_ -> "default printing"
-- note that we cannot access the Prop record of our items in the _ case
view raw _.elm hosted with ❤ by GitHub

Let's take back the Item example and let's pretend that we want to create a new kind of Item : milestone. Say milestones do not have start date but are just used as deadlines. Say my app is pretty developed and I am doing a lot of things on my Item and use the underscore matching a lot. By adding a new kind of Item in my union type I'd expect the compiler to throw a bunch of errors at my face directly which will not happen in that case: my new kind Milestone would already be matched by the _ so there will not be anything wrong that will be caught by the compiler. Yet I probably don' t want my Milestone items to be dealt with like any other items… So I would have to resolve to looking up for any _ and make sure that I adapt the code manually.

The replacement

Use let … in! (or make another helper function)… It really is as simple as that… instead of making multicase matching, put the common treatment in a function within the let ... in or put it outside if the treatment is consequent and use it afterwards:

assignTo : String -> Item -> Item
assignTo user task =
let
updateAssignee taskProperties =
{ taskProperties | assignee = Just user }
in
case task of
Task props ->
Task (updateAssignee props)
SubTask props ->
SubTask (updateAssignee props)
Bug props ->
Bug (updateAssignee props)
Epic props ->
Epic props -- i.e. remain unchanged
view raw assignTo.elm hosted with ❤ by GitHub

And voilà ! It sounds pretty stupid but I hope it helps!

Here is a small "project" showing this… nothing fancy, only one message and one button.

AWS Q Developer image

Your AI Code Assistant

Automate your code reviews. Catch bugs before your coworkers. Fix security issues in your code. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

Top comments (0)

AWS Q Developer image

Your AI Code Assistant

Generate and update README files, create data-flow diagrams, and keep your project fully documented. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

Instrument, monitor, fix: a hands-on debugging session

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

Tune in to the full event

DEV is partnering to bring live events to the community. Join us or dismiss this billboard if you're not interested. ❤️