Generic Functions

Felicity Johnson
5 min readNov 7, 2016

--

I recently worked with the map function and noticed that its default return type is “T.” After some investigation (ie. Stackoverflow search), I discovered that the “T” stands for a placeholder type and that the map function is generic. At first I thought to myself “Great!” Then my next thought was “but wait, what is a generic function… 🤔 ” If you’re wondering the same thing, then read on!

Before we breakdown generic functions, let’s first (briefly) discuss generic code. Per Apple’s documentation, “Generic code enables you to write flexible, reusable functions and types that can work with any type, subject to requirements that you define.” Two generics that you are likely familiar with are arrays or dictionaries — both collection types allow you to work with any type. For example, one dictionary may be of type [String: String], while another may be of type [String: Double]. Similarly, an array could be of type [Int], or of type [Float]….you get the picture. Following this logic, generic functions are functions that take in any type as parameters and return any type.

If you look at the function above, you may notice that the calculateMinimum function only works for type Int. If I want to use the exact same logic with type Float or type Double, I would have to make two additional functions for each type. This seems silly to repeat the same code more than once, right? Apple thought so as well, which is why the concept of generic functions was introduced.

Generic Parameter(s) and Generic Return Type

The genericCalculateMinimum function above is the exact same as calculateMinimum with two exceptions. Firstly, instead of taking in parameters of type Int and returning type Int, genericCalculateMinimum takes in parameters of type “T” and returns type “T.” The “T” written in <> tells Swift that the parameter of type “T” is actually just a placeholder type. Therefore, Swift knows to infer the type based on the inputs within the function when the function is called. For example, if we look at the first print statement above with inputs of 4 and 2, Swift infers that 4 and 2 are of type Int. Since the function is returning “T,” Swift’s inference of the parameter type allows it to return the correct type as well. Therefore, in this case it returns a value of type Int. Within the function if you tried to set valueToReturn to a Bool instead, then you would receive an error because Bool cannot be converted into this function’s correct return type of Int.

Similarly, Swift infers from the last print statement that the parameters are of type String and therefore it returns a value of type String. You may be wondering why “hello” is printed as the minimum value instead of “yes.” This is because Swift calculates the “value” of strings based on the string’s hash value. Per Apple’s documentation, a “…hash value is an Int value that is the same for all objects that compare equally…” In plain English, hash value enables the comparison of two variables of the same type. String, Int, Double, and Bool types all have access to the hashValue property by default. Check out Alex’s blog to read more about hash values and the Hashable protocol.

The second difference between the two functions above is that genericCalculateMinimum conforms to the Comparable protocol.

Quick Side-Bar Summary: Comparable and Equatable Protocols:

Apple states in its documentation that the Comparable protocol “…is used for types that have an inherent order, such as numbers and strings.” Any time “==”, “<”, and “>” are used in a function, the function must conform to the Comparable protocol. The Comparable protocol inherits from the Equatable protocol. Types that conform to the Equatable protocol can be compared for equality or inequality using “==” and “!=”, respectively.

You may be saying to yourself “but I have used ‘==’,’<’, and ‘>’ within functions before and have not explicitly stated that the function conforms to the Comparable protocol…?” This is because generic functions allow for any type to be used; however, not all types are able to perform the task within the function. For instance, in the example above, if I pass two different classes into genericCalculateMinimum and try to compare the two, I may receive an error similar to the one below; since the Cat class does not conform to the Comparable protocol, I am not able to compare the two within the generic function. However, if the Cat class DID conform to the Comparable protocol, genericCalculateMinimum would have run smoothly!

The key takeaway from this is that additional parameters sometimes need to be added to generic functions if you would like it to perform certain actions. Though generic functions with additional parameters still take any type, you must make sure that the type is able to perform the task that you have written within the generic function. Don’t worry — XCode lets you know if you have forgotten to add an additional parameter! 😉

Generic Parameter(s) and Set Return Type

What if you would like the parameters to be generic but you know the function’s return type? No problem! As you can see from the code below, you can be flexible with which elements you want to be generic. In this example, I am able to input any two properties of the same type and the function will perform the comparison and return a Bool.

You may be asking yourself if you can also have set parameter(s) and return a generic type. The answer is NO! Though certain functions (like the map function) return type “T” when Xcode auto-completes the closure, you must change the type from “T” to whatever specific return type you would like in order for the function to run.

If you would like to read more about generic functions, click here to check out Apple’s documentation.

--

--