Beauty of Swift

Today I am going to talk about couple of Swift tricks I learned recently. First one is about operator associativity and how Swift handles it gracefully to error it out during compile time and other is how function overloading is so much fun in Swift

Operator Associativity

We all know operator associativity decides the order or direction in which expression is evaluated. If could either be left of right associative.

For example, let's assume that operator == has a left associativity.

x == y == z

== being a left associative, expression will be regarded as

(x == y) == z

So whatever the result of left most expression, this will be applied to next operand in the row. So specifying associativity helps compiler evaluate expressions in more predictive way.

However, it turns out Swift does not specify any associativity for == operator which makes it really confusing to evaluate expressions such as,

x == y == z

So if you type this example, compiler will complaint to avoid any potential bug. Point here is that lack of associativity makes this expression confusing since order of execution for subsets of expression is undefined. Thus compiler raises an error flag.

Let's clarify it more so that compile will understand it better and will also be less prone to any potential bugs.

(x == y) == z or x == (y == z)

Now depending on your requirement you can specify the order of execution for above statement. Swift will just follow the code and prioritize the expression evaluation based on the position of circular braces

This is important, since braces act as a fix for lack of associativity for our operator. This is one of the examples which demonstrates how Swift can help developers tackle bugs in early stages of development cycle. Had it been any other ordinary language, the lack of compiler error would've introduced a bug in our code. Warnings, as opposed to compiler errors are easy to ignore. However, by converting it to errors, Swift makes it impossible for developers to ignore such seemingly innocuous but fatal programming practices

Function Overloading

As opposed to Objective-C Swift introduces a long missed feature of function overloading. As Wikipedia describes it

function overloading or method overloading is the ability to create multiple methods of the same name with different implementations. Calls to an overloaded function will run a specific implementation of that function appropriate to the context of the call, allowing one function call to perform different tasks depending on context

Let's see one such example of overloaded functions in Swift,


class FunctionOverloading {

    func customPrint() {
        print("Printing nothing")
    }

    func customPrint(number: Int) {
        print("Printing number \(number)")
    }

    func customPrint(name: String) -> String {
        print("Printing string \(name)")
        return "Printed"
    }
}

class FuncOverloadingDemo {
    func mainMethod() {
        let overloading = FunctionOverloading()
        overloading.customPrint()
        overloading.customPrint(number: 100)
        _ = overloading.customPrint(name: "Swift 3.0")
    }
}

In the above example, when mainMethod is called, it will produce following output

"Printing nothing"
"Printing number 100"
"Printing string Swift 3.0"

As evident from method signatures, all of them have same name, but they differ in terms of arguments and return types. Thus, this is classic example of function overloading implemented in the Swift.

Now, let's consider another case of overloaded functions returning different types, but taking same arguments


func blackBoxNumber() -> Int {
        return 100
}

func blackBoxNumber() -> Float {
    return 100.0
}

Now let's see what happens when you try to call one of the functions

Compiler throws following error for our beautiful code

SampleSwiftCode/FunctionOverloading.swift:42:30: Ambiguous use of 'blackBoxNumber()'

Why? It turns out we have two functions with same name, but different arguments. When you make a call to blackBoxNumber, compiler is confused which function to make call to.

It turns out this is fairly easy problem to deal with by explicitly specifying the associated type either to left side operand or casting the result of operation to desired type.


let blackBoxOutputInt = overloading.blackBoxNumber() as Int
let blackBoxOutputFloat = overloading.blackBoxNumber() as Float

//OR

let blackBoxOutputInt: Int = overloading.blackBoxNumber()
let blackBoxOutputFloat: Float = overloading.blackBoxNumber()

Please note how function overloading is resolved at compile time in Swift is opposed to runtime as it is done in Objective-C. This enables developer to catch errors in early stage as again highlighted in the first example above

These two examples should be enough for this blog post to demonstrate the beauty and power Swift offers. Some naive developers might think that language is too restrictive. But it's restrictive for a reason and to force careless developers to follow the righteous path towards spotless code

If you have any questions about this post or general programming, please do not hesitate to reach out to me. I am usually active on Twitter or the quickest contact would be to reach me by my email. I am looking forward to hear your thoughts on mobile development

Reference:

Facets of Swift