Extending system types to reduce code

Another powerful feature that we briefly covered in Chapter 3, One Piece at a Time – Types, Scopes, and Projects is the ability to extend existing types. We saw that we could add an extension to the string type that would allow us to repeat the string multiple times. Let's look at a more practical use case for this and discuss its benefits in terms of improving our code.

Perhaps we are creating a grade-tracking program where we are going to be printing out a lot of percentages. A great way to represent percentages is by using a float with a value between zero and one. Floats are great for percentages because we can use the built-in math functions and they can represent pretty granular numbers. The hurdle to cross when using a float to represent a percentage is printing it out. If we simply print out the value, it will most likely not be formatted the way we would want. People prefer percentages to be out of 100 and have a percent symbol after it.

Worst case scenario, we are going to write something, such as print("(myPercent * 100)%"), every time we need to print out a percentage. This is not very flexible; what if we wanted to tweak all percentage outputs to have leading spaces, so it prints out right aligned? We would have to go through and change every print statement. Instead, we could write our own function like printPercentage. This will allow us to share the same code in lots of places.

This is a good step, but we can do one better using Swift's ability to extend system types. If we have an arbitrary function called printPercentage, we are going to have a hard time remembering it is there and other developers will have a hard time discovering it in the first place. It would be much nicer if we could easily get a printable version of a float directly from the float itself. We can make this possible by adding an extension to Float:

extension Float {
    var percentString: String {
        return "(self * 100)%"
    }
}
let myPercent: Float = 0.32
print(myPercent.percentString) // 32.0%

Now we can use auto-complete to help us remember what formats we have defined for a float. Over time, you will probably develop a collection of useful and generic extensions like this that are extremely reusable because they are independent of any of your other program specific code. Writing these in such a reusable way makes it very easy to bring them into a new program, greatly accelerating each new project you start.

However, you do want to be careful that you don't end up creating too many extensions. For more complex situations, it is often more appropriate to use the composite pattern instead. For example, we could have written this as a Percent type that can be constructed with a Float:

struct Percent: CustomStringConvertible {
    let value: Float

    var description: String {
        return "(self.value * 100)%"
    }
}
print(Percent(value: 0.3))

In this case it may not warrant the complexity of its own class, but you should at least consider how you might want to extend the idea of a percentage in the future.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset