Ambiguity passing `Any?` to generic constructor


(Jens Alfke) #1

I’m making a little utility struct that needs to be able to wrap an arbitrary value, which may be an optional, and be able to tell whether it’s nil. So I declared it like this (I’ve removed the interesting/useful parts of the code leaving just the constructors and one property):

public struct check<T> {
    let actual: T?

    public init(_ a: T) {
        actual = a
    }

    public init(_ a: T?) {
        actual = a
    }

    public var isNil: Bool {
        return actual == nil
    }
}

This works fine, except when I try to use it with a value of type `Any?`:

let str: String = "Hi"
check(str).isNil // false

let maybe: String? = nil
check(maybe).isNil // true

let hmm: Any? = nil
check(hmm).isNil // Error: “Ambiguous use of ‘init'"

(I agree that `Any?` is sort of a weird type; in my code it represents a value that might be a JSON object. NSJSONSerialization parses to type `Any`, but there might not be a value, so it becomes an Optional<Any> or Any?.)

This worked in Swift 2.2, but after upgrading to Swift 3 [in the latest Xcode 8 beta] the compiler started complaining.

How can I fix the `check` struct's constructor(s) to make this work?

—Jens


(Zhao Xin) #2

You can just remove

    public init(_ a: T) {
        actual = a
    }

It is redundant. Below code works.

public struct check<T> {

    let actual: T?

//

// public init(_ a: T) {

// actual = a

// }

    public init(_ a: T?) {

        actual = a

    }

    public var isNil: Bool {

        return actual == nil

    }

}

let str: String = "Hi"

check(str).isNil // false

let maybe: String? = nil

check(maybe).isNil // true

let hmm: Any? = nil

check(hmm).isNil // true

Zhaoxin

···

On Mon, Aug 29, 2016 at 11:39 PM, Jens Alfke via swift-users < swift-users@swift.org> wrote:

I’m making a little utility struct that needs to be able to wrap an
arbitrary value, which may be an optional, and be able to tell whether it’s
nil. So I declared it like this (I’ve removed the interesting/useful parts
of the code leaving just the constructors and one property):

public struct check<T> {
    let actual: T?

    public init(_ a: T) {
        actual = a
    }

    public init(_ a: T?) {
        actual = a
    }

    public var isNil: Bool {
        return actual == nil
    }
}

This works fine, except when I try to use it with a value of type `Any?`:

let str: String = "Hi"
check(str).isNil // false

let maybe: String? = nil
check(maybe).isNil // true

let hmm: Any? = nil
check(hmm).isNil // Error: “Ambiguous use of ‘init'"

(I agree that `Any?` is sort of a weird type; in my code it represents a
value that might be a JSON object. NSJSONSerialization parses to type
`Any`, but there might not be a value, so it becomes an Optional<Any> or
Any?.)

This worked in Swift 2.2, but after upgrading to Swift 3 [in the latest
Xcode 8 beta] the compiler started complaining.

How can I fix the `check` struct's constructor(s) to make this work?

—Jens

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users