switch case and === operator

I have the following code:

func numberOfRows(in tableView: NSTableView) -> Int {
        switch tableView {
        case self.stringsTable:
            return self.stringsList?.count ?? 0
        case self.localeTable:
            return self.localeMap.count
        default:
            print("numberOfRows not handled for \(tableView)")
            return 0
        }
    }

I wonder if there is any (performance) difference between case and ==== operator like below:

func numberOfRows(in tableView: NSTableView) -> Int {
        if tableView === self.stringsTable {
        }
        // ...
    }
Answered by Claude31 in 764828022

I did the following test (Xcode simulator), for a table declared as IBOutlet:

    func numberOfSections(in tableView: UITableView) -> Int {
        var start = CFAbsoluteTimeGetCurrent()
        for _ in 0..<1000_000 {
            if table == tableView { }
        }
        var diff = CFAbsoluteTimeGetCurrent() - start
        print("==", diff)
        
        start = CFAbsoluteTimeGetCurrent()
        for _ in 0..<1000_000 {
            if table === tableView { }
        }
        diff = CFAbsoluteTimeGetCurrent() - start
        print("===", diff)
        
        return 1
    }

I get the following values:

== 0.7980579137802124
=== 0.647942066192627

I repeated the test with a tableView declared in code:

    var testTableView: UITableView = UITableView()
    func numberOfSections(in tableView: UITableView) -> Int {
        var start = CFAbsoluteTimeGetCurrent()
        for _ in 0..<1000_000 {
            if table == tableView { }
        }
        var diff = CFAbsoluteTimeGetCurrent() - start
        print("==", diff)
        
        start = CFAbsoluteTimeGetCurrent()
        for _ in 0..<1000_000 {
            if table === tableView { }
        }
        diff = CFAbsoluteTimeGetCurrent() - start
        print("===", diff)

        
        start = CFAbsoluteTimeGetCurrent()
        for _ in 0..<1000_000 {
            if testTableView == tableView { }
        }
        diff = CFAbsoluteTimeGetCurrent() - start
        print("== testTableView", diff)

        start = CFAbsoluteTimeGetCurrent()
        for _ in 0..<1000_000 {
            if testTableView === tableView { }
        }
        diff = CFAbsoluteTimeGetCurrent() - start
        print("=== testTableView", diff)

        return 1
    }

This time, may be because testTableView is empty, === was faster:

== 0.7994720935821533
=== 0.6421390771865845
== testTableView 0.5936309099197388
=== testTableView 0.6272460222244263

In any case, difference is about 1/10 of a millionth…

Is your question about === vs == ?

=== should be faster, as it has only to compare 2 pointers. Hence second should be faster than switch case.(see in JavaScript: https://stackoverflow.com/questions/19041946/why-faster-than-in-javascript#:~:text=So%20%3D%3D%3D%20faster%20than%20%3D%3D%20in%20Javascript&text=%3D%3D%3D%20compares%20if%20the%20values,27%2C%202013%20at%202%3A59)

But if tableView is an IBOutlet, == should also compare references (https://stackoverflow.com/questions/42552958/comparing-instances-of-uitableview-in-swift-. Hence the same speed.

To get precise result, you should try by calling a 100_000 times the function in each case. In any case,it would be surprising it has any impact that user can notice.

Accepted Answer

I did the following test (Xcode simulator), for a table declared as IBOutlet:

    func numberOfSections(in tableView: UITableView) -> Int {
        var start = CFAbsoluteTimeGetCurrent()
        for _ in 0..<1000_000 {
            if table == tableView { }
        }
        var diff = CFAbsoluteTimeGetCurrent() - start
        print("==", diff)
        
        start = CFAbsoluteTimeGetCurrent()
        for _ in 0..<1000_000 {
            if table === tableView { }
        }
        diff = CFAbsoluteTimeGetCurrent() - start
        print("===", diff)
        
        return 1
    }

I get the following values:

== 0.7980579137802124
=== 0.647942066192627

I repeated the test with a tableView declared in code:

    var testTableView: UITableView = UITableView()
    func numberOfSections(in tableView: UITableView) -> Int {
        var start = CFAbsoluteTimeGetCurrent()
        for _ in 0..<1000_000 {
            if table == tableView { }
        }
        var diff = CFAbsoluteTimeGetCurrent() - start
        print("==", diff)
        
        start = CFAbsoluteTimeGetCurrent()
        for _ in 0..<1000_000 {
            if table === tableView { }
        }
        diff = CFAbsoluteTimeGetCurrent() - start
        print("===", diff)

        
        start = CFAbsoluteTimeGetCurrent()
        for _ in 0..<1000_000 {
            if testTableView == tableView { }
        }
        diff = CFAbsoluteTimeGetCurrent() - start
        print("== testTableView", diff)

        start = CFAbsoluteTimeGetCurrent()
        for _ in 0..<1000_000 {
            if testTableView === tableView { }
        }
        diff = CFAbsoluteTimeGetCurrent() - start
        print("=== testTableView", diff)

        return 1
    }

This time, may be because testTableView is empty, === was faster:

== 0.7994720935821533
=== 0.6421390771865845
== testTableView 0.5936309099197388
=== testTableView 0.6272460222244263

In any case, difference is about 1/10 of a millionth…

There are a couple of interesting things to note here.

  1. Because UITableView is a subclass of NSObject, === just compares pointers (as Claude pointed out), but == invokes the Obj-C method (on NSObject) isEqual:. However, it's very likely UITableView just inherits the default implement of isEqual:, which … simply compares the pointers! IOW, the only difference in performance should be that == involves an Obj-C method dispatch, while === doesn't. The performance overhead of method dispatch is really small, so the slight different that Claude measured seems reasonable.

  2. The switch statement doesn't actually use the == operator, since the case is chosen using the pattern matching operator ~=. By default, the pattern matching operator is going to do an equality check under the hood, so the actual performance is probably going to depend a little bit on how well the compiler was able to optimize the switch statement.

So, a pretty interesting question.

switch case and === operator
 
 
Q