0

I have following line in my code:

for (i = 0, j = count - 1; i < count; j = i++)

Can anyone help to remove the two compiler warnings, that i++ will be removed in Swift 3.0 and C-style for statement is depreciated?

Oliver Apel
  • 1,808
  • 3
  • 19
  • 31
  • 2
    Many examples in this Q&A: http://stackoverflow.com/questions/36166907/replacement-for-c-style-loop-in-swift-2-2 – Eric Aya Jul 13 '16 at 14:39

4 Answers4

5

You could use this:

var j = count-1
for i in 0..<count {
    defer { j = i } // This will keep the cycle "logic" all together, similarly to "j = i++"

    // Cycle body
}

EDIT

As @t0rst noted, be careful using defer, since it will be executed no matter how its enclosing scope is exited, so it isn't a 100% replacement.

So while the standard for ( forInit ; forTest ; forNext ) { … } will not execute forNext in case of a break statement inside the cycle, a return or an exception, the defer will.

Read here for more

Alessandro Orrù
  • 3,443
  • 20
  • 24
  • 2
    Great use of `defer`. – Luca Angeletti Jul 13 '16 at 15:16
  • 1
    ⚠️ Watch out: `defer` is intended for safe clean-up, and as such will be executed no matter how its enclosing scope is exited. Replacing `for ( forInit ; forTest ; forNext ) { … }` with `forInit; while forTest { defer { forNext } … }` will give different behaviour: a) the defer block is executed when you break from the loop, so the state of your iterator variables is no longer the same as when your loop exit condition was satisfied, and b) the defer block is executed if you exit via an exception, which would be a problem in the unlikely case your `forNext` statement has side effects. – t0rst Oct 13 '16 at 20:16
  • @t0rst that is true, but of course you don't have to blindly copy and paste code without understanding what it means. This is just another tool in your toolbox, and in most cases it is a clean and elegant solution. – Alessandro Orrù Oct 14 '16 at 14:06
  • @AlessandroOrrù re: "blindly copy and paste code without understanding what it means" — you expect _everyone_ to understand? Statistically not very likely. Good structures reduce cognitive load and don't require developers to be hyper-vigillant for errors, more than they are already. Without my warning comment above, the casual reader might assume that `defer` would do what they wanted — some will double check, others will not, and an error scenario may not show until the use of `defer` is long since forgotten. `defer` is not a 'clean' solution here - you have to use and document it with care. – t0rst Oct 14 '16 at 14:15
  • @t0rst sorry, that wasn't meant against *you*. It was a general warning: never blindly copy code, especially a simple line like this, without understanding what it means. Every "solution" out there for this or other questions must be used with care. In any case I edit my original post to add a note about the effects. – Alessandro Orrù Oct 14 '16 at 14:18
  • @AlessandroOrrù I absolutely agree. But I also think that time and attention is such a scarce resource and in so much demand that there is a high probability that some, not all, will miss the pitfalls. With a precise understanding of how `defer` works it is very useful. – t0rst Oct 14 '16 at 14:24
  • @t0rst I agree. Your initial warning just seemed to me more like a: hey, this is dangerous, don't use it. Now I understand better your point of view, that's why I edited my post to add some notes ;) – Alessandro Orrù Oct 14 '16 at 14:26
  • @AlessandroOrrù just seen your edit to the original answer - everyone forewarned now – t0rst Oct 14 '16 at 14:26
1

Alternatively, lets go crazy to avoid having to declare j as external to the loop scope!

Snippet 1

let count = 10

for (i, j) in [count-1..<count, 0..<count-1].flatten().enumerate() {
    print(i, j)
}
/* 0 9
   1 0
   2 1
   3 2
   4 3
   5 4
   6 5
   7 6
   8 7
   9 8 */

Snippet 2

for (i, j) in (-1..<count-1).map({ $0 < 0 ? count-1 : $0 }).enumerate() {
    print(i, j)
}
dfrib
  • 70,367
  • 12
  • 127
  • 192
1

Trying to win the prize for the craziest solution in this thread

Snippet 1

extension Int {
    func j(count:Int) -> Int {
        return (self + count - 1) % count
    }
}

for i in 0..<count {
    print(i, i.j(count))
}

Snippet 2

let count = 10
let iList = 0..<count
let jList = iList.map { ($0 + count - 1) % count }

zip(iList, jList).forEach { (i, j) in
    print(i, j)
}
Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
  • 1
    I wont even post the thoroughly escalated snippet #3 in any other form than a comment:) `for (i, j) in (1-count..= 0 }).map(abs).enumerate() { print(i, j) }` – dfrib Jul 13 '16 at 15:58
  • @dfri: I believe a code obfuscation tool could hardly do better than _snippet#3_ :D – Luca Angeletti Jul 13 '16 at 16:01
  • 1
    I had to refactor it from the first `flatMap` version for the compiler to handle it (v.1 ; too complex :D). Thanks for the fun, I actually like your snippet 1 above, extension ftw! – dfrib Jul 13 '16 at 16:04
1

You could use a helper function to abstract away the wrapping of j as:

func go(count: Int, block: (Int, Int) -> ()) {
  if count < 1 { return }
  block(0, count - 1)
  for i in 1 ..< count {
    block(i, i - 1)
  }
}
Pyry Jahkola
  • 613
  • 3
  • 5