I have two almost exactly identical assertions for a generic method on Swift's Dictionary structure, but one succeeds and the other fails. I assume that it's how XCTAssert works, but can't understand why. Does anyone have an idea why?
If the method is not generic and, for example, T is String, then both tests 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 was tinkering with it a little bit more, and it turns out that if you pass a type as a parameter, then both cases succeed. But I imagine this type verbosity is not that one would want.
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")
}
}
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 XCTAssertEqual's argument is declared as @autoclosure expression1: () -> T?, so the compiler tries to pick a version of safeElement that returns an optional, which it can do easily by making T==String?. But then your as? T does the wrong thing, since the dictionary's Value type is a non-optional String.
Sounds like a bug.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With