3

I'd like to create a function that will iterate over an array (or collection or sequence). Then I will call that function with an array, and the reversed version of the array (but efficiently: without creating a new array to hold the reverse).

If I do this:

func doIteration(points: [CGPoint]) {
  for p in points {
     doSomethingWithPoint(p)
  }
  // I also need random access to points
  doSomethingElseWithPoint(points[points.count-2]) // ignore obvious index error
}

And if I have this:

let points : [CGPoint] = whatever

I can do this just fine:

doIteration(points)

But then if I do this:

doIteration(points.reverse())

I get 'Cannot convert value of type 'ReverseRandomAccessCollection<[CGPoint]> to expected argument type [_]'

Now, I DON'T want to do this:

let reversedPoints : [CGPoint] = points.reverse()
doIteration(reversedPoints)

even though it will work, because that will (correct me if I'm wrong) create a new array, initializing it from the ReverseRandomAccessCollection returned by reverse().

So I guess I'd like to write my doIteration function to take some sort of sequence type, so I can pass in the result of reverse() directly, but ReverseRandomAccessCollection doesn't conform to anything at all. I think I'm missing something - what's the accepted pattern here?

1
  • doIteration(points.reverse()) does compile. What you probably meant is let rev = points.reverse() ; doIteration(rev) which causes the error message that you described. Commented Dec 1, 2015 at 19:11

2 Answers 2

2

If you change your parameter's type to a generic, you should get the functionality you need:

func doIteration
  <C: CollectionType where C.Index: RandomAccessIndexType,  C.Generator.Element == CGPoint>
  (points: C) {
  for p in points {
    doSomethingWithPoint(p)
  }
  doSomethingElseWithPoint(points[points.endIndex - 2])
}

More importantly, this won't cause a copy of the array to be made. If you look at the type generated by the reverse() method:

let points: [CGPoint] = []

let reversed = points.reverse() // ReverseRandomAccessCollection<Array<__C.CGPoint>>

doIteration(reversed)

You'll see that it just creates a struct that references the original array, in reverse. (although it does have value-type semantics) And the original function can accept this new collection, because of the correct generic constraints.

Sign up to request clarification or add additional context in comments.

Comments

0

You can do this

let reversedPoints : [CGPoint] = points.reverse()
doIteration(reversedPoints)

or this

doIteration(points.reverse() as [CGPoint])

but I don't think there is any real difference by the point of view of a the footprint.

Scenario 1

let reversedPoints : [CGPoint] = points.reverse()
doIteration(reversedPoints)

Infact in this case a new Array containing references to the CGPoint(s) present in the original array is created. This thanks to the Copy-on-write mechanism that Swift used to manage structures.

So the memory allocated is the following:

points.count * sizeOf(pointer)

Scenario 2

On the other hand you can write something like this

doIteration(points.reverse() as [CGPoint])

But are you really saving memory? Let's see. A temporary variable is created, that variable is available inside the scope of the function doIteration and requires exactly a pointer for each element contained in points so again we have:

points.count * sizeOf(pointer)

So I think you can safely choose one of the 2 solutions.

Considerations

We should remember that Swift manages structures in a very smart way.

When I write

var word = "Hello"
var anotherWord = word

On the first line Swift create a Struct and fill it with the value "Hello". On the second line Swift detect that there is no real reason to create a copy of the original String so writes inside the anotherWord a reference to the original value.

Only when word or anotherWord is modified Swift really create a copy of the original value.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.