Sid Mani
Sid Mani

Reputation: 369

Why are where clauses only valid on functions with generic parameters?

It seems absurd that this method signature does not compile in Swift 4:

class Bar<ValueType> { 
    func version() throws -> String where ValueType == [String: Any] { ... }
}   

(Error: where clause cannot be attached to a non-generic declaration)
but this compiles fine:

class Bar<ValueType> { 
   func version<T>(_ foo: T? = nil) throws -> String where ValueType == [String: Any] { ... }  
} 

Anyone have insight as to why this is the case?

Upvotes: 5

Views: 5210

Answers (2)

Boris
Boris

Reputation: 181

That has been finally allowed in Swift 5.3. See Contextual Where Clauses in the official Language Guide.

Citing from there:

You can write a generic where clause as part of a declaration that doesn’t have its own generic type constraints, when you’re already working in the context of generic types. For example, you can write a generic where clause on a subscript of a generic type or on a method in an extension to a generic type.

...

extension Container {
    func average() -> Double where Item == Int {
        var sum = 0.0
        for index in 0..<count {
            sum += Double(self[index])
        }
        return sum / Double(count)
    }

That compiles just fine in Xcode 12 beta 4, but won't work in Xcode 11.6 that is shipped with Swift 5.2.4.

Upvotes: 2

Alexander
Alexander

Reputation: 63271

Because ValueType has nothing to do with this method (in the first example). It would be wrong to put such a method in a type (class/struct/enum), since it's not really a true member of that type. It's conditionally a member of that type, depending on the truth value of the where clause.

To achieve this, you would want to put this method in an extension of your type, with the where clause you want. E.g.

extension YourType where ValueType == [String: Any] {
    func version() throws -> String { ... }
}

Upvotes: 3

Related Questions