A new Swift video series exploring functional programming and more.
#12 • Monday Apr 16, 2018 • Subscriber-only

Tagged

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.

#12 • Monday Apr 16, 2018 • Subscriber-only

Tagged

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.


Subscribe to Point‑Free

This episode is for subscribers only. To access it, and all past and future episodes, become a subscriber today!

See subscription optionsorLog in

Sign up for our weekly newsletter to be notified of new episodes, and unlock access to any subscriber-only episode of your choosing!

Sign up for free episode

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.

Subscribe to Point-Free

👋 Hey there! Does this episode sound interesting? Well, then you may want to subscribe so that you get access to this episodes and more!


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

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