Clean Coding in Swift – Type Inference

Quick!  Tell me!  What is the Type of the  birdDetails constant in this code example:

With no additional context to glean information from, the correct answer to the question is, “I have absolutely no clue…”  Or is it?

“Not fair!”, you say.  “In the real world, I’d have the ability to option-click and learn the type from a pop-up tooltip, or learn this information by inspection from XCode’s utilities panel.”

Truth.  We would.  But… should we have to for an example like the one above?  Could we have helped ourselves out a bit by being explicit about the type of birdDetails?

This was the question I asked myself as I set out to determine how and when I prefer to explicitly specify the Types of my variables and constants at declaration-time, rather than letting the compiler infer the Type for me.

Type Inference is powerful and convenient.  It enables us to leave off explicit type specifications when we declare a variable or constant, leaving us with nice, terse, clean-looking code.  But in reality, for examples like the one posed above, is clean-looking truly “clean code”?

From Apple’s documentation:

Type inference enables a compiler to deduce the type of a particular expression automatically when it compiles your code, simply by examining the values you provide.

The key phrase that stuck out to me was this:  “Type inference enables a compiler to deduce the type of a particular expression…”.  Humans are not compilers!

I don’t know about you, but I could use all the help I can get when it comes to figuring out simple things like the Type resulting from an expression.  Sure, I could rely on the IDE, but in debugging, or in trying to simply read and understand what the intention of my code is when I come back to it sometime later, I want to focus on the code, not on pop-up tool tips or inspector panels.

For instances where deducing the type is not simple for a human to do (and I mean really simple), I’m getting to where I prefer to specify the Type up-front.  We’re used to doing this in Objective-C, and I even do it in C# when using  var would obscure things.  When a language gives me the option to be clear about Types, I try to take advantage of that valuable language feature for all but the simplest of situations.

The Simplest of Situations

Let’s think for a moment about this so-called “simplest of situations”.  I would define such a situation to be when the Type resulting from an expression can easily, at a glance, be inferred by a human being without assistance from an IDE.  It’s all about context here, and for these simplest of situations, I love Type Inference.

Compare the following two lines of code:


In the example just presented, typing “ : String ” to explicitly specify birdDetails’ type is superfluous in my opinion (and I prefer not to be repetitively redundant when I can).  It’s crystal clear that birdDetails in this example is a String.

However, in situations like the one at the beginning of the article where, by simply looking, I would have to answer, “I have no clue what the Type of this is”, my preference / proposal for your consideration would be to go ahead and specify the Type at declaration time.  Consider:

When I’m writing this the first time, I can spend the time looking up the function’s return Type and specify it when I declare my constant.  It will make my life so much easier down the road.

Don’t stumble over the fact that birdDetails is a  tuple type (String, String) .  The point is that the function could have returned anything, and it would still have been impossible for me to tell you what the Type of the constant was just by looking, had I not specified it upon its declaration.

Being explicit about the type in the declaration has great potential to immediately help us get our bearings around a particular set of code when we return to it after any length of time.  And it seems to me that one of the principal goals of writing clean code is to help ourselves and our teams make sense of code quicker so that everyone’s happier and more productive.

Whew.  That was a long-winded exploration of some things to think about when relying on (or avoiding) Type Inference in your own code.  Thanks for reading!

Since publishing this op-ed, I’ve expanded my thoughts on Type Inference as it relates to clean coding practices in Swift.  I highly recommend that this post be read and considered alongside my latest musings,which were heavily influenced by Rob Napier’s comments below.

  • Phillip Flores

    I completely agree. I’d rather be explicit my declarations because I know down the track I will be saving time and possibly angst when I have to revisit my code because I do not have to figure out what type my declarations are.

    • Andrew Bancroft

      A few extra keystrokes at the front-end is worth saving brain cells later, right? :]

      Thanks for reading and sharing your thoughts on this! So do you just go ahead and specify the type -always-, even for the let x = “aString” kind of declarations? Do you find value there? Just curious…

      • Phillip Flores

        Coming from a Delphi and C# background wherein I have to explicitly specify the variable types even for the string types it feels odd to just write var x = “aString”. Reminds me a bit of BASIC. I usually write var x = String(); Out habit I suppose.

  • bret3d

    I’m with you, too. For primitives implicit is fine, but it rubs me the wrong way that any code that is harder to read could be beneficial (unless there are performance reasons which this is not).

  • I tend to agree on you even thought there is just one sentence that I didn’t like “A simple copy-paste from the function..”. I feel nervous about the idea of copy-and-past code in generale while coding because it means repeat more then once the same “information” that usually have problem if you need to refactor your code. To be specific, in you case if you decide to change the return type of your function you need to remember to update all the place where you explicated the type, it’s also true that the compiler will complain if you don’t do so but still is a friction point for iterating fast.

    • Andrew Bancroft

      Very valid points, Luca – and I agree with you. I’ll try and revise this section when I get a few free moments.

  • Pingback: Sort Yourself Out – Sorting an Array in Swift | Andrew Bancroft()

  • robnapier

    I agree with where you’re going here, but there’s a deeper issue to consider. The underlying problem with this code is that the tuple is a poor type. If you created a struct called BirdDetails, then all the rest of the issues would go away because the return type would be obvious again. So I agree that type inference should only be used when the result is unambiguous, but the best solution is to make the result unambiguous. When this can’t be done, then explicit typing is the next-best solution.

    • Andrew Bancroft

      This is awesome – I appreciate your deeper analysis here, Rob.

      So basically, what you’re saying about the example in the post is, “Don’t do that to a function’s return type.” – haha

      In other words, be predictable with your function return types for your own sake. The function signature should be such that when I write “birdDetailsFromStorage()”, that -name- in itself is my clue that the return type is something like your proposed BirdDetails Struct. Is this a good summary of your analysis?

      If this is a correct interpretation then I’m with you. Seems like a good convention-based approach to give humans the right clues about variable/constant assignments from function returns.

      Type inference is totally legitimate to embrace if the right context cues are in place to make its usage unambiguous.

      • robnapier

        You nailed it. A function called birdDetailsFromStorage() should return a BirdDetails. There are exceptions, but they should be consistent and obvious. Like birdNameFromSomething() could return a String if there were no such thing as “BirdName” or “Name” in the system. “Name” often implies “String”. But don’t go implying that you’re returning one thing when you’re returning another. If you must, then yes, explicit types are your punishment 😀

  • Pingback: Expanded Thoughts on Swift’s Type Inference | Andrew Bancroft()

  • Pingback: 7 Reasons You Should Write About Swift | Andrew Bancroft()