Swift: Money with Phantom Types 👻

When I wrote about enums with no cases yesterday, both @mbrandonw and @jl_hfl pointed me to Phantom Types 👻!

I’ve seen Phantom Types before, including in this objc.io article about Phantom Types and in conference talks, but while I like the idea of Phantom Types and think they’re cool and interesting, I haven’t actually used them ever in my own code. Mostly, because it’s not yet natural for me to see a problem and think “Ah, Phantom Types would be the perfect solution!”.

However, I would like to have Phantom Types more accessible for myself in the future and I really enjoyed the example that @johannesweiss gave in his talk The Type System is Your Friend, so I’m going to write his example out here to be more searchable / discoverable for myself and hopefully others!

The problem that @johannesweiss with Phantom Types is currency conversion 💸🤑💸!

While in the video, @johannesweiss goes straight into the Phantom Type solution, I wanted to first try a solution without the Phantom Types to see the before and after!

Without Phantom Types 😱

I would probably have a Money struct that includes both the amount and the currency of the amount:

But let’s say I want to convert the money to a different currency – let’s say from GBP to EUR:

We can immediately see the problem. I have to check to make sure that the money passed into my function is of the correct currency. And if it’s not, I have to trhow an Error. Which cascades down and now the function that calls this function has to handle an error case!

With Phantom Types 👻

Phantom Types are Types that don’t have any functionality. According to @johannesweiss:

A phantom type is a parameterized type whose type parameters do not all appear in its definition. I have what you could call a useless type parameter C. This is the Currency, and it is not even used in the actual properties of the struct. To fill Money, I created an empty protocol, Currency, so that I may mark any type as a currency.

Like this:

Now the GBP -> EUR conversion function looks like this!

Notice that we no longer need to manually check for correct currency type or return any errors. The compiler does the work for us!

Update

The point of this blog post is to illustrate the basics of using Phantom Types. However, as @oisdk points out, you can go further and use Phantom Types to automatically pick the correct conversion:

@davedelong further optimized the solution to this:

Enjoy the article? Join over 20,000+ Swift developers and enthusiasts who get my weekly updates.