Tagged

Episode #12 • Apr 16, 2018 • Subscriber-Only

We typically model our data with very general types, like strings and ints, but the values themselves are often far more specific, like emails and ids. We’ll explore how this can lead to subtle runtime bugs and how we can strengthen these types in an ergonomic way using several features new to Swift 4.1.

Tagged
Introduction
00:05
Decodable
00:53
Raw representable
07:11
Tagged
13:54
What’s the point?
23:26

Unlock This Episode

Our Free plan includes 1 subscriber-only episode of your choice, plus weekly updates from our newsletter.

Introduction

We often work with types that are far too general or hold far too many values than what is necessary in our domains. In our past episode on algebraic data types we used algebra to help simplify certain types to chisel them down to their core essentials. However, sometimes that isn’t possible. Sometimes we just want to differentiate between two seemingly equivalent values at the type level.

For example, an email address is nothing but a string, but it should be restricted in the ways in which it can be used. Also, ids in our code may all be integers, but it doesn’t make sense to compare a user’s id with, say, a subscription id. They are completely different entities.

We want to show that Swift, and in particular Swift 4.1, gives us an incredible tool to lift types up to a higher level so that they can distinguished from each other more easily. This helps improve the contracts we are building into our functions and methods, and overall makes our code safer.

This episode is for subscribers only.

Subscribe to Point-Free

Access this episode, plus all past and future episodes when you become a subscriber.

See plans and pricing

Already a subscriber? Log in

Exercises

  1. Conditionally conform Tagged to ExpressibleByStringLiteral in order to restore the ergonomics of initializing our User’s email property. Note that ExpressibleByStringLiteral requires a couple other prerequisite conformances.

  2. Conditionally conform Tagged to Comparable and sort users by their id in descending order.

  3. Let’s explore what happens when you have multiple fields in a struct that you want to strengthen at the type level. Add an age property to User that is tagged to wrap an Int value. Ensure that it doesn’t collide with User.Id. (Consider how we tagged Email.)

  4. Conditionally conform Tagged to Numeric and alias a tagged type to Int representing Cents. Explore the ergonomics of using mathematical operators and literals to manipulate these values.

  5. Create a tagged type, Light<A> = Tagged<A, Color>, where A can represent whether the light is on or off. Write turnOn and turnOff functions to toggle this state.

  6. Write a function, changeColor, that changes a Light’s color when the light is on. This function should produce a compiler error when passed a Light that is off.

  7. Create two tagged types with Double raw values to represent Celsius and Fahrenheit temperatures. Write functions celsiusToFahrenheit and fahrenheitToCelsius that convert between these units.

  8. Create Unvalidated and Validated tagged types so that you can create a function that takes an Unvalidated<User> and returns an Optional<Validated<User>> given a valid user. A valid user may be one with a non-empty name and an email that contains an @.

References

Tagged

Brandon Williams & Stephen Celis • Monday Apr 16, 2018

Tagged is one of our open source projects for expressing a way to distinguish otherwise indistinguishable types at compile time.

Tagged Seconds and Milliseconds

Brandon Williams • Wednesday Jul 18, 2018

In this blog post we use the Tagged type to provide a type safe way for interacting with seconds and milliseconds values. We are able to prove to ourselves that we do not misuse or mix up these values at compile time by using the tagged wrappers.

Type-Safe File Paths with Phantom Types

Brandon Kase, Chris Eidhof, Florian Kugler • Thursday Oct 5, 2017

In this Swift Talk episode, Florian and special guest Brandon Kase show how to apply the ideas of phantom types to create a type safe API for dealing with file paths. We’ve used phantom types in our episode on Tagged to provide a compile-time mechanism for distinguishing otherwise indistinguishable types.

Downloads

Sample Code

0012-tagged