Search code examples
swiftargumentsios8sequenceios8-extension

Swift: Missing argument in call to argumentless extension of SequenceOf


Can anybody see light on this bug? The playground insists that argument #2 is missing, but there is no argument #1!

The intention of the code to to count the number of runs of a equatable value, and return a sequence of tuples consisting of the values and their counts. I've worked on this code extensively, optimising it and refining it until I'm pretty sure that it should work… but although it compiles, I cannot call it the way it was intended.

The error i get from calling the code below is missing argument for parameter #2 in call

extension SequenceOf {
    func CountRuns<T: Equatable>() -> SequenceOf<(T, Int)> {
        return SequenceOf<(T, Int)>([])
        return SequenceOf<(T, Int)> { () -> GeneratorOf<(T, Int)> in
            var generator = self.generate()
            var previousValue: T?
            var start = true
            return GeneratorOf<(T, Int)> { () -> (T, Int)? in
                var count = 1
                var retValue: (T, Int)?
                while(true) {
                    var value = generator.next() as T?
                    if start {
                        previousValue = value
                        start = false
                    } else if value != nil && value! == previousValue! {
                        count++
                    } else {
                        if previousValue != nil {
                            retValue = (previousValue!, count)
                        }
                        previousValue = value
                        break
                    }
                }
                return retValue
            }
        }
    }
}

println(SequenceOf(y).CountRuns())

Playground execution failed: <EXPR>:327:23: error: missing argument for parameter #2 in call
println(SequenceOf(y).CountRuns())
                      ^

Solution

  • The problem you're having is that you can't actually extend a generic type with a method that further specializes its generic subtype. That is to say, your countRuns method requires that SequenceOf's generic subtype T be Equatable, but you can only provide those constraints in the original type declaration, not in an extension.

    The solution is to declare countRuns as a top-level function, like so:

    func countRuns<T: Equatable>(s: SequenceOf<T>) -> SequenceOf<(T, Int)> {
        return SequenceOf<(T, Int)> { () -> GeneratorOf<(T, Int)> in
    
            // note the change from self.generate() to s.generate() here
            var generator = s.generate()
    
            var previousValue: T?
            var start = true
            return GeneratorOf<(T, Int)> { () -> (T, Int)? in
                var count = 1
                var retValue: (T, Int)?
                while(true) {
                    var value = generator.next() as T?
                    if start {
                        previousValue = value
                        start = false
                    } else if value != nil && value! == previousValue! {
                        count++
                    } else {
                        if previousValue != nil {
                            retValue = (previousValue!, count)
                        }
                        previousValue = value
                        break
                    }
                }
                return retValue
            }
        }
    }
    
    println(countRuns(SequenceOf(y)))
    

    This was covered (a little) at the end of this NSHipster article.