Implementing "Either" struct in Swift
swift
Solution
This has been fixed in Beta 3, the last case now correctly triggers a compiler error forcing you to specify the generic type explicitely
The problem is in types - when creating `Either` from literals:
let b4 = Either(first: nil, second: nil)
then the compiler can't infer the type for the `nil` parameters. If you check the debugger, you will see that the inferred type is a type called `_Nil`.
(lldb) p b4
(SwiftConsole.Either<_Nil, _Nil>) $R1 = {
first = Some
second = Some
}
Now, this is a type which accepts `nil` but it is not an optional type itself.
let x: _Nil = nil //this is not an optional
The initialiser is making an optional of it, thus making a value `Optional.Some(nil)` and because it's a `.Some(...)` value, comparing it with `nil` will be `false`.
I don't see any easy generic workarounds but in this case it would help to specify generic types explicitly:
let b4 = Either<String, Int>(first: nil, second: nil)
I suggest you report a bug because this is just silly. Instead of inferring some special types which lead to undefined behaviour, the compiler should instead trigger an error.
The same problem would arise with type `Any` because it can also accept `nil` without being an optional.
let x: Any = nil //this is not an optional
Either<Any, Any>(first: nil, second: nil).which() //true !!!
Edit: This will be fixed in Beta 3. `nil` will be made a literal, `_Nil` type will be removed and `_Any` won't accept `nil` any more.
Confirmed here: https://devforums.apple.com/thread/234463?tstart=0
Problem
Can someone explain what is happening in the code below? It creates a struct `Either` which takes any two optional types and (attempts to) return whichever one is not nil, or the first if both are not nil. However, it behaves strangely when passing literal nil as opposed to a nil variable in. I can't see why `b4` in the example behaves as it does... ``` struct Either <T1, T2> { let first: T1? let second: T2? init(first: T1?, second: T2?) { self.first = first self.second = second } func either() -> Bool { return (self.first != nil) || (self.second != nil) } func which() -> Any? { if self.first != nil { return self.first } else if self.second != nil { return self.second } return nil } } var s1: String? = nil var s2: Int? = nil let b1 = Either(first: s1, second: s2) b1.either() // false b1.which() // {nil} s1 = "Hello" let b2 = Either(first: s1, second: s2) b2.either() // true b2.which() // {Some Hello} s1 = nil s2 = 7 let b3 = Either(first: s1, second: s2) b3.either() // true b3.which() // {Some 7} // all as expected, however let b4 = Either(first: nil, second: nil) b4.either() // true !!! <<<<<<<<<<<<<<<<<< b4.which() // {nil} ``` I think it has to do with "Optional Optionals", but I'm not sure it's behaving as expected.