Unlock This Episode
Our Free plan includes 1 subscriber-only episode of your choice, plus weekly updates from our newsletter.
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.
ExpressibleByStringLiteralin order to restore the ergonomics of initializing our
ExpressibleByStringLiteralrequires a couple other prerequisite conformances.
Comparableand sort users by their
idin descending order.
Let’s explore what happens when you have multiple fields in a struct that you want to strengthen at the type level. Add an
Userthat is tagged to wrap an
Intvalue. Ensure that it doesn’t collide with
User.Id. (Consider how we tagged
Numericand alias a tagged type to
Cents. Explore the ergonomics of using mathematical operators and literals to manipulate these values.
Create a tagged type,
Light<A> = Tagged<A, Color>, where
Acan represent whether the light is on or off. Write
turnOfffunctions to toggle this state.
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
Lightthat is off.
Create two tagged types with
Doubleraw values to represent
Fahrenheittemperatures. Write functions
fahrenheitToCelsiusthat convert between these units.
Validatedtagged 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
Tagged is one of our open source projects for expressing a way to distinguish otherwise indistinguishable
types at compile time.
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.
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.