Benchmark of Swift extensions vs methods: Swift 4.1 (May 2018)

Oleksandr Prokhorenko
3 min readMay 25, 2018
Interactive charts are available here: http://minikin.me/extensions

🤼‍ Motivation

A few weeks ago I had a discussion with an iOS programmer whom has many strong beliefs. One of them sounds like: “Use of Swift extensions is very bad practice due to compilation times dramatically increasing and decreases readability and code clarity”. I’m not going to judge about readability and clarity. Those are personal style preferences, but I was quite confused with the argument about compilation time. I recall there were discussions about the topic three or more years ago. Three years for Swift, sounds to me, like 50 years for mankind. I was quite sure that the situation is not as bad as this person thinks, because I know that the Swift team continuously improves language, including compilation time. I’m not such a person which is going to argue without having solid arguments.

👨🏻‍🔬 Benchmarking

Last weekend, I had a few hours free to check his statement. I wrote a ruby script to check the performance of extensions vs methods. The approach which I selected is quite simple, probably even naive, but anyway I’d like to see some results. I checked the following cases:

  • Class + Methods
  • Class + Extensions
  • Struct + Methods
  • Struct + Extensions

Ruby script create n number functions for each case (in example n=3):

Class + Methods

class MyClass {
let n = 1000
func method_1() {
for item in 0..<n { let newItem = item + 2; print(newItem)}
}
func method_2() {
for item in 0..<n { let newItem = item + 2; print(newItem)}
}
func method_3() {
for item in 0..<n { let newItem = item + 2; print(newItem)}
}
}

Class + Extensions

class MyClass {
let n = 1000
func method_1() {
for item in 0..<n { let newItem = item + 2; print(newItem)}
}
}

extension MyClass {
func method_ext_1() {
for item in 0..<n { let newItem = item + 2; print(newItem)}
}
}
extension MyClass {
func method_ext_2() {
for item in 0..<n { let newItem = item + 2; print(newItem)}
}
}
extension MyClass {
func method_ext_3() {
for item in 0..<n { let newItem = item + 2; print(newItem)}
}
}

I also wanted to know the answer to the question: How many extensions are in real-world Swift apps? I checked the most popular open-sourced applications written in Swift and few applications which we developed in our company for clients for a number of extensions.

* — our apps have about these numbers of extensions

To run tests set USE_EXTENSIONS to true or false in Rakefile.

Run tests:

rake benchmark

Cleanup tests results:

rake clean

📈 Results

When it came to representing collected data in a clear and meaningful way, my data science skills were quite handy. I created a python script main.py which generates bokeh charts.

Interactive charts are available here: http://minikin.me/extensions
Results

Testing environment: macOS 10.13.4 , Swift 4.1, 2016 MacBook Pro, 2.6 GHz Intel Core i7, 16 GB 2133 MHz LPDDR3

🧐 Conclusions

On average, use of methods approach is between -6% — 70% as fast as the equivalent implementation with extensions.

But does this mean that we shouldn’t use Extensions? Probably not.
In real applications, the count of extensions rarely reach 1000, and if they do, the difference is about 20%.

Sure, in a real application we’ll have different results, but measured in absolute time difference, the savings are unlikely to be appreciable under most circumstances.

If you want to experiment you can check the repo on GitHub.

If you have any questions, please feel free to contact me: @minikin

Update 1 (03.06.2018):

Yarik Arsenkin asked me to add benchmark for case Class + Private Functions in Extension vs Class + Private Methods. Please, check updated charts and results.

--

--