XCTAssert with generic method in Swift

I have two almost exactly identical statements for a general method in a Swift framework Dictionary

, but one succeeds and the other fails. I am assuming it works XCTAssert

, but cannot figure out why. Anyone have an idea why?

If the method is not generic and is, for example, T

equal String

, then both tests will succeed.

extension Dictionary {
    func safeElement<T>(key: Key, fallback: T) -> T {
        if let value = self[key] as? T {
            return value
        }
        return fallback
    }
}

class DictionaryTests: XCTestCase {
    let dict = ["foo": "bar"]

    func testSafeElement() {
        // This succeeds
        let bar = dict.safeElement("foo", fallback: "")
        XCTAssertEqual(bar, "bar")

        // This fails
        XCTAssertEqual(dict.safeElement("foo", fallback: ""), "bar")
    }
}

      

Update

I did a bit of tinkering with this, and it turns out that if you pass the type as a parameter, then both cases will succeed. But I guess this type of verbosity is not what I would like.

extension Dictionary {
    func safeElement<T>(key: Key, fallback: T, type: T.Type) -> T {
        if let value = self[key] as? T {
            return value
        }
        return fallback
    }
}

class DictionaryTests: XCTestCase {
    let dict = ["foo": "bar"]

    func testSafeElement() {
        // This succeeds
        let bar = dict.safeElement("foo", fallback: "", type: String.self)
        XCTAssertEqual(bar, "bar")

        // This also succeeds
        XCTAssertEqual(dict.safeElement("foo", fallback: "", type: String.self), "bar")
    }
}

      

+3


source to share


1 answer


If you add a print statement:

func safeElement<T>(key: Key, fallback: T) -> T {
    print("calling for \(T.self)")

      

You can see the difference in output between the two tests:



calling for String
calling for Optional<String>

      

This is probably because the XCTAssertEqual argument is declared as @autoclosure expression1: () -> T?

, so the compiler tries to pick a version safeElement

that returns an optional parameter, which is easy to do by creating a T==String?

. But then yours is as? T

doing the wrong thing as the value type of the dictionary is optional String

.

Sounds like a mistake .

+2


source







All Articles