A (better) Swift Equivalent For The Classical For-Loop With Numeric Scalars


(Jon Hull) #1

I would also like to see some real world use cases from numerics packages. This may be something we can solve by providing a series of customizable generators. Stride might work for a subset of use cases, but I don’t think we should try to shoehorn everything into it.

I have generally been using map when I need an arbitrary function:
  
  for i in (1…10).map({$0 ** 2})

It may not be the most efficient, but I have also used where:

  for i in 1…10 where i % 3 != 0

Having to put the ( ) around the range does lessen the readability a bit, but I think the following is reasonable:

  for i in (1…10).by(2)

You could argue to make a new form of for-in-by which only operates on ranges, but not sure it is worth the complexity:

  for i in 1…10 by 2

What about just providing a generator which has exactly the same semantics as the for;; loop had? I am bad at naming things, so feel free to mentally substitute a better name:

  func Loop<T>(start:T, end: @autoclosure (T)->bool, step: @autoclosure (T)->T) -> GeneratorOf<T>
  
Which would be used like:

  for i in Loop(start:0, end: $0 < 10, step: $0 + 1)

Ack… I just realized @autoclosure doesn’t work when you have a parameter. Is there a particular reason for that? Without @autoclosure it would be the much less pretty:

  for i in Loop(start:0, end: {$0 < 10}, step: {$0 + 1})

One last option would be to supply bounds instead of a closure and a few special cases:

  func Loop<T>(start:T, bounds: Range<T>, step: (T)->T) -> GeneratorOf<T>
  func Loop(start:Int, bounds:Range<Int>, step:Int) -> GeneratorOf<T>
  func Loop(start:Double, bounds: Range<Double>, step:Double) -> GeneratorOf<T>

  for i in Loop(start: 0, bounds: 0…10, step: 2)

The special cases could easily optimize (by returning a different generator) so only the upper/lower bound has to be checked in the range based on the sign of the step.

Thanks,
Jon
Note: All code written in Mail.app, so please excuse any bugs