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")
}
}
source to share
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 .
source to share