Unexpected behavior of variadic parameters

class Test {
    func test() {
        print("test")
    }
    
    func test(_ values: Int...) {
        print(values)
    }
}

let t = Test()
t.test() // prints test

However if func test() is implemented in extension of Protocol, it behaves different.

protocol P {
    func test()
}

extension P {
    func test() {
        print("test")
    }
}

class Test: P {
//    func test() {
//        print("test")
//    }
    
    func test(_ values: Int...) {
        print(values)
    }
}

let t = Test()
t.test() // prints []

Please file a bug report: bugs.swift.org

I filed SR-10573.

1 Like

I'm not sure this is really "unexpected". Swift rules for name resolution is that the "most specific" symbol gets picked. Let's examine these cases:

:one:

Test.test // works only in no arguments case
Test.test(...) // works with any number of arguments

Test().test() // zero arguments is more specific

:two:

P.test // Works for any type conforming to `P`
Test.test(...) // works with any number of arguments

Test().test() // `P` one is more specific on the number of arguments, `Test` one is more specific on the type of the caller. It seems like the language gives priority to the latter

I agree, but it does confuse me. I encountered a bug with this. At first my code only has zero arguments implemented in extension, and it works fine. Then I added a variadic one, I have never expected it will mess all my code. It is not easy to what influence it will bring. This is what I want to express here by using "unexpected".

I tried other examples. I think it's better to forbid to call test() with the variadic one.

protocol P {
    func test()
}

extension P {
    func test() {
        print("test")
    }
}

class Test: P {
    func test(values: Int...) {
        print(values)
    }
}

let t = Test()
t.test(values: 1, 2, 3) // prints [1, 2, 3]

but why

t.test() // prints []

still call the variadic one, since it doesn't contain label.

1 Like

Uff did this really worked in Swift 4.x?

class Test  {
  func test(_ values: Int...) {
    print(values)
  }
}

let test = Test()
test.test()

It does compile and run in Swift 5, but I'm really surprised that this is allowed in first place. Sure the array can be empty, but is variadic parameter list really allowed to be empty?

struct Something {
  subscript (values: Int...) -> Void {
    print(values)
  }
}

let s = Something()
s[] // oh no

this is unexpected to me...

I think it always was

Calling a variadic func with zero arguments is allowed?

class Test {
    func test(_ values: Int...) {
        print("1.", values)
    }
}
let tt = Test()
t.test() // 1. []

What if labeled func?

class Test {
    func test(values: Int...) {
        print("2.", values)
    }
}
let t = Test()
t.test() // 2. []

Labeled func should be different from unlabeled one. Then how to call the second one?

let t = Test()
t.test(values:) // ???

Also

class Test  {
    func test(_ values: Int...) {
        print("1.", values)
    }
    
    func test(values: Int...) {
        print("2.", values)
    }
}

let t = Test()
t.test(1, 2) // 1. [1, 2]
t.test(values: 1, 2) // 2. [1, 2]

t.test() // Ambiguous use of 'test'. Why?