Interested in making your Swift builds faster? Check out my book Faster Swift Builds, coming soon!

What is Type Inference?

Take a look at this line of code:

What does x represent? Is it a string of text, a numeric value, some custom object? Without more context you really can't say. If you could see the implementation of makeValue() that would offer some clues but it could just be the tip of the iceberg. You may need to read an awful lot more code just to understand what x is supposed to represent.

And that is what the compiler is doing here. This line of code - with that additional context - does compile in Swift. Swift has "type inference". The compiler infers the likely type of x from how it is used. As you might imagine, this can be a lot of work for the compiler. It may need to analyze a very large slice of the complete codebase to infer the correct type for x.

In many Swift projects the widespread use of type inference significantly impacts the amount of time required to complete a build. Take a look at the average build times for three large internal projects.





How do we get to that point? What can we do to make our projects take less time like the green bars on the chart? Take a look at this line of code:

That's all there is to fixing it. Adding a type annotation to the variable tells the compiler that x represents a String. It does not have to infer anything here - and the code is that much more readable to humans. The code builds faster and is easier to maintain.

Type inference is a convienience for those learning to program - and it comes with a significant cost.

Xcode 9 and 10 can show where type inference is taking "too long" . In your project configuration:

OTHER_SWIFT_FLAGS = $(inherited) - Xfrontend -warn-long-expression- type -checking=100

... to see where type inference is taking more than 100 milliseconds during compilation. In practice this isn't very useful - it will show individual type checks that take more than 100ms. There may be thousands of lines that have type inference in your project. In a large project even small type checking overhead adds up quickly. 20ms of type checking in a large codebase can easily add up to seconds of project compilation time. warn-long-expression-type-checking is best used for prioritzing fixes rather than discovering problems.

Fixing Type Inference in Your App

Fixing type inference is simple: add the correct type annotations just like we just saw. Finding where type inference is being used in your code - and preventing it from being reintroduced - will take some extra help.

SwiftLint is an open source tool that can be used to enforce a set of coding style rules in a Swift project. When integrated with Xcode it can show rule violations directly in the source editor:

Install SwiftLint by following the instructions in the README file available on GitHub. The instructions include how to use a shell script build phase to integrate SwiftLint into your Xcode project.

SwiftLint can detect the use of type inference using the explicit_type_interface rule. For the sake of this example we want only that rule active, no other rules should run. whitelist_rules: turns off all rules but those we specify in the configuration file.

In your project folder create a new file, .swiftlint.yml. SwiftLint will use this as the configuration file for your project. Add the following lines to it:

whitelist_rules: - explicit_ type _interface

Build your project in Xcode and you should begin seeing warnings coming from SwiftLint. For a large project this can be overwhelming - there may be hundreds or even thousands of warnings. Type annotations should be added for each violation. Plan your work carefully and divide it among your team. Once you are down to zero type inference violations keep the SwiftLint rule in place, if only on your Continuous Integration server. You don't want to allow type inference to make its way back into your codebase later.

Interested in making your Swift builds faster? Check out my book Faster Swift Builds, coming soon!