Turning Property Wrappers into Function Wrappers

Vincent Pradeilles
Dec 28, 2019 · 3 min read
Thanks to undraw.co for a great illustration

If you’re keeping up with the new features of Swift, you’ve probably heard of Property Wrappers. They have introduced a few months ago as part of Swift 5.1 and we’ve covered their basics in a previous article.

Property Wrappers & Functions

Today, we’re going to take things a bit further by exploring an unexpected use case of Property Wrappers!

Now, the name Property Wrapper can be slightly deceiving, because when we read Property, we intuitively think of data.

And this makes sense because when we write code in Swift our primary use case for properties is to store data. However, we shouldn’t forget that, in Swift, function types are the first-class citizens. Meaning that the signature of a function is a type with the same features as any other Swift type. Consequently, it is perfectly legal to store a function inside a property, as follows:

This fact bears a very interesting consequence: since functions can be stored inside properties, it means that Property Wrappers could also be made to work with functions 🎉

So let us take a look at the kind of construct this approach could enable us to build.

As an example, we’ll be implementing something that is rather straightforward to understand: a caching mechanism.

To begin, we are going to define a struct called Cached:

For the moment, this struct does nothing more than storing a function. To turn it into a Property Wrapper, we'll decorate it with the attribute @propertyWrapper:

The compiler is now going to ask us to implement a wrappedValue:

Its getter is straightforward to implement: we just return our stored function. The actual caching logic is going to be implemented inside the setter:

So what’s happening inside this setter? First, we declare the cache that will store the results of our computations. To keep things simple, we’ll use a Dictionary, with a Key and Value that respectively match the Input and Output of the function, we want to cache.

Then, the actual caching logic is pretty simple to follow: when the cachedFunction is called, we take its argument and look it up in our cache. If we find a match, we return the value we had previously stored. Otherwise, we perform the computation, store the result in the cache, and return it.

(You might be wondering why the variable cache is not defined as a private var of the struct. The explanation is simple: the cache is being mutated inside an escaping closure, which is not allowed for properties of a struct. By defining and scoping it inside a function, we avoid this issue.)

Finally, you can notice that we’ve also defined an init. It performs the same job than the setter, and allows us to add our caching logic right when the wrapper is first instantiated.

Now that our wrapper has been implemented, we can try it out:

And if we run this code, we’ll indeed see that our caching mechanism is working as expected 🎉

We are now able to define custom wrappers that will decorate pieces of our code and bring them additional behavior in a very seamless way! To some extent, we could say that we’ve built our first Function Wrapper 🚀

To Conclude

In this article, we took the example of implementing a caching mechanism, but we could cover many more use cases: for instance, we could implement wrappers like @Delayed(delay: 0.3) and @Debounced(delay: 0.3), to deal with the timing of code execution. Or we could provide thread safety via a wrapper @ThreadSafe, that would wrap the execution of a piece of code around a Lock.

The possibilities are basically endless, and now it’s up to you to think of and implement the Function Wrappers that will make sense inside your own codebase 💪

You liked this article and you want to see more content like it? Feel free to follow me on Twitter: https://twitter.com/v_pradeilles

Flawless iOS

🍏 Community around iOS development, mobile design, and…

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

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