-1

I have a very large list of numbers and I would like to pass it to a function to do some manipulations to it. Originally, I created a function with an inout property. As many know, inout in swift does NOT pass by reference, rather it makes an initial copy to the function then copies the values back on the return. This sounds expensive. I decided to wrap my list in a class and pass by reference in order to optimize and reduce time for copying. Interestingly enough, it seems that the inout function is faster than the pass by reference function. I even make a manipulation to the inout variable to cause the compiler to copy-on-write. Any ideas why the inout function is faster than the pass by reference?

class ReferencedContainer {
    var container = [Int:Bool]()
}

func printTimeElapsedWhenRunningCode(title:String, operation:()->()) {
    let startTime = CFAbsoluteTimeGetCurrent()
    operation()
    let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
    print("Time elapsed for \(title): \(timeElapsed) s.")
}

func inoutTest(list: inout [Int]?) -> [Int]? {
    list![0]=1
    return list
}

func refTest(list: ReferencedContainer) -> ReferencedContainer {
    list.container[0] = true
    return list
}


var list : [Int]? = [Int]()
for i in 0...10000 {
list?.append(i)
}

var ref = ReferencedContainer()
for i in list!
{
    ref.container[i] = true
}
printTimeElapsedWhenRunningCode(title: "refTest", operation: { refTest(list: ref)})

printTimeElapsedWhenRunningCode(title: "inout", operation: { inoutTest(list: &list)})

Time elapsed for refTest: 0.0015590190887451172 s.

Time elapsed for inout: 0.00035893917083740234 s.

EK_AllDay
  • 1,095
  • 2
  • 15
  • 35
  • 1) Usual spiel about premature optimization 2) are you testing this with optimizations enabled? – Alexander Jun 25 '19 at 03:54
  • Also, you're optimizing the wrong things. Your repeated append calls are causing multiple array resize operations, each causing a copy of all of the elements. – Alexander Jun 25 '19 at 03:56
  • Why the down vote? – EK_AllDay Jun 25 '19 at 04:47
  • Wasn't me, but probably about number 1 – Alexander Jun 25 '19 at 13:40
  • @Alexander can you elaborated on "usual spiel about premature optimization" so i dont make the same mistake. – EK_AllDay Jun 25 '19 at 18:57
  • You're blindly optimizing off of hunches (and in this case, an incorrect hunch), rather than taking a data-driven approach, optimizing things that a profiler actually shows to be an issue. Your optimization of passing by ref to avoid copies is basically completely irrelevant compared to the optimization opportunity you missed, which is to pre-allocate a sufficiently large array at the beginning, to prevent multiple array resizing operations (each one of which will cause a copy of all of the elements)/ – Alexander Jun 25 '19 at 22:24
  • @Alexander But my question is about inout and it's implications vs pass by ref. I'm not interested in other aspects or optimizations – EK_AllDay Jun 27 '19 at 00:31
  • 1
    And that's fine, I'm just answering your question "can you elaborated on "usual spiel about premature optimization"" – Alexander Jun 27 '19 at 02:45
  • @Alexander I understand, I wish I didnt get a down vote for the "usual spiel" etc – EK_AllDay Jun 27 '19 at 16:48
  • Likewise. So has your question been answered? You haven't accepted any o fit answers yet – Alexander Jun 27 '19 at 21:48

2 Answers2

2

As many know, inout in swift does NOT pass by reference, rather it makes an initial copy to the function then copies the values back on the return. This sounds expensive.

It's not. It's copying an instance of a [Int: Bool] (a.k.a. Dictionary<Int, Bool>) which is only a single pointer. See for yourself, with print(MemoryLayout<[Int: Bool]>.size).

Alexander
  • 59,041
  • 12
  • 98
  • 151
2

Two things to consider, out of many possible:

  1. inout may use call-by-reference as an optimisation, see In-Out Parameters
  2. Your two tests are rather different, one uses optionals and an array, the other a dictionary. You're also only testing a single mutation, try doing more. The only difference you should have is struct vs. class and if you try that you can get similar speeds or one of them faster than the other – either way around.
CRD
  • 52,522
  • 5
  • 70
  • 86