Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing an enum ForwardIndexType

Tags:

enums

swift

I have been struggling to properly implement the ForwardIndexType protocol for an enum, in particular the handling of the end case (i.e for the last item without a successor). This protocol is not really covered in the Swift Language book.

Here is a simple example

enum ThreeWords : Int, ForwardIndexType {
    case one=1, two, three

    func successor() ->ThreeWords {
            return ThreeWords(rawValue:self.rawValue + 1)!
    }
}

The successor() function will return the next enumerator value, except for the last element, where it will fail with an exception, because there is no value after .three

The ForwardTypeProtocol does not allow successor() to return a conditional value, so there seems to be no way of signalling that there is no successor.

Now using this in a for loop to iterate over the closed range of all the possible values of an enum, one runs into a problem for the end case:

for word in ThreeWords.one...ThreeWords.three {
    print("   \(word.rawValue)")
}
println()

//Crashes with the error:

fatal error: unexpectedly found nil while unwrapping an Optional value

Swift inexplicably calls the successor() function of the end value of the range, before executing the statements in the for loop. If the range is left half open ThreeWords.one..<ThreeWords.three then the code executes correctly, printing 1 2

If I modify the successor function so that it does not try to create a value larger than .three like this

   func successor() ->ThreeWords {
        if self == .three {
            return .three
        } else {
            return ThreeWords(rawValue:self.rawValue + 1)!
        }
    }

Then the for loop does not crash, but it also misses the last iteration, printing the same as if the range was half open 1 2

My conclusion is that there is a bug in swift's for loop iteration; it should not call successor() on the end value of a closed range. Secondly, the ForwardIndexType ought to be able to return an optional, to be able to signal that there is no successor for a certain value.

Has anyone had more success with this protocol ?

like image 229
Guy Brooker Avatar asked Nov 01 '14 07:11

Guy Brooker


1 Answers

Indeed, it seems that successor will be called on the last value.

You may wish to file a bug, but to work around this you could simply add a sentinel value to act as a successor.

like image 200
jtbandes Avatar answered Sep 18 '22 05:09

jtbandes