Guarding against an empty sequence

On Swift-Users yesterday, someone asked how to guard against an empty sequence. The context of the question was how to test a sequence against a predicate and the problem was that an empty sequence returned true for satisfying the predicate.

Now, leaving aside the entire question of the base behavior (which I believe is correct since no element in an empty sequence fails to satisfy the predicate), I thought Jeremy Pereira came up with an especially cute solution:

func all(@noescape where predicate: Generator.Element throws -> Bool) rethrows -> Bool {
	var count = 0
       for element in self {
	    guard try predicate(element) else { return false }
	    count += 1
       }
       return count > 0
}

One of the big questions though that grew out of the discussion was “how do you non-destructively test a sequence for being empty?”  My answer to this was to use a buffer with look-ahead. Here’s my first shot at this, completely a rough draft and open for any improvement suggestions you might offer.

public struct BufferedSequence<Base : SequenceType>:GeneratorType, SequenceType {
    
    internal var _base: Base
    internal var _generator: Base.Generator
    public var bufferedElement: Base.Generator.Element?
    
    public init(_ base: Base) {
        _base = base
        _generator = base.generate()
        bufferedElement = _generator.next()
    }

    public mutating func next() -> Base.Generator.Element? {
        defer {
            if bufferedElement != nil {
                bufferedElement = _generator.next()
            }
        }
        return bufferedElement
    }
    
    public func isEmpty() -> Bool {
        return bufferedElement == nil
    }
}

Interestingly enough, the most difficult thing in throwing this little thing together was not trying to think about look-ahead but to translate  Swift 3 idioms back to Swift 2.2 so I could mess with this in a playground.

How is the transition going for you? Are you all 3’ed up yet? Or are you still holding firm in 2.2 land and writing production code?

3 Comments

  • Swift 2.2.1 (or whatever the App Store’s got in ‘store’) for production. Eagerly latest snapshot for not-production-ready-yet they’ll-eventually-be-ready personal projects. ^__^

    • How are you doing the mental switchover? It’s absolutely killing me

  • I would make all of the internal state private i.e. _base and _generator would be private. bufferedElement would be public private(set). Other than that, this is pretty much as I would write it, except I wouldn’t have thought of the clever use of defer { … }.

    The struct has applications beyond merely testing that a sequence is empty non destructively, I think. It could, for example be used to wrap a token stream for a recursive descent parser for an LL(1) grammar.