With* Functions in Elm

With* functions are functions that take the shape of
withProperty : Prop -> CustomType -> CustomType. When several are chained together using the pipeline operator they tend to produce terse, yet legible, code and a pleasant API.

Let’s consider some code that is a good candidate to refactor to use this pattern. Here is a module that exposes a configurable button.

This example shows several permutations of a button by leveraging an API that is expecting the following configurable record to be passed in.

Here we see a handful of optional properties which leads to somewhat verbose code at the call site. Examples like this are a great opportunity to use with* functions!

At a high level, any property that is optional for a button will be considered for turning into a with* function. Prior to that step let’s start with the required properties. What are the required properties of a button? Based on the above example, this is the list that I came up with.

  • label : String
  • onClick : Msg

That’s it! Did you come up with the same list? What about size? Surely a button must know what size to render at. Or whether it should render as disabled or not.

While both of those statements are true for rendering a button, when I mention required property what I’m really getting at are required properties that do not have reasonable defaults. All of the other properties can either be left out entirely or they have reasonable default values.

Cool. Let’s get to refactoring and start off by defining a custom type and a default constructor function.

Now that we have a way of creating a default button (with reasonable defaults!) let’s add some with* functions to allow for configurability.

Admittedly, some of those function names read slightly awkwardly. The goal of this pattern isn’t necessarily to be dogmatic about using “with” as a prefix. Rather, this pattern is more about producing a pleasant API and separating required properties that don’t have safe defaults from other properties.

Below is an alternate API that might be more pleasant to use and read.

Is the above better? Maybe 🤷‍♂️! Discuss it with your team and find out what will work best for you!

Finally, we show all button permutations while leveraging the function pipeline operator and our new with and make functions for a more pleasant API.

And everything all put together in Ellie!

Summing up some benefits

This approach works particularly well in situations when using a module that has a lot of optionality. In the above example we explored this approach with a UI element that intrinsically had many optional properties but this can also be true of other things like web requests, especially GraphQL.

Other benefits include:

  • Encouraged use of hiding implementation details behind an opaque type
  • As a result of the above point, versioning UI elements has fewer backwards incompatible changes. Imagine adding an optional icon in both examples. When using the above pattern all exposed function type annotations stay the same with the exception that the module would also expose a new withIcon function.
  • The code tends to be just as readable, if not more readable
  • The code tends to be more terse especially at call sites that do not need to heavily override default values
  • This approach can be very convenient with unit testing. If you’re not heavily writing fuzz tests this is a nice way to quickly mock up different inputs for passing to functions

Additional resources




Software Architect | Conference Speaker | Blog Author

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

An Introduction To Svelte

10 Basics of JavaScript Interview Questions That you need to know!

#100DaysOfCode Day 33: Connecting Front-End to Back-End using Axios, An Inquiry on Ports.

Working To-Do list application made with MERN Stack.

Commit conventions

Master RxJS: Frontend data stores in services using BehaviorSubject

10 Most JavaScript Interview Question

3 Weird Signs of a Lame Programmer

How to Install React on Linux Manjaro

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Charlie Koster

Charlie Koster

Software Architect | Conference Speaker | Blog Author

More from Medium

Setting-up Vroom & OSRM with docker-compose

Telos Oracle & Data Logging Service (data.scribe)

Complete guide creating APIs using grpc-js and grpc-web with typescript

Building a Wordle Solver