I want to write an enum like Optional, but when I try to cast Codable value "a" to Optionally, it always failed with warning: "Cast from 'any Codable' (aka 'any Decodable & Encodable') to unrelated type 'Optionally' always fails". However, using the system Optional will not have corresponding warnings. What's the difference? How to fix my code?
public enum Optionally<T> {
case none
case value(T)
}
extension Optionally: Codable where T: Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let value = try? container.decode(T.self) {
self = .value(value)
} else {
self = .none
}
}
public func encode(to encoder: Encoder) throws {
if case .value(let value) = self {
var container = encoder.singleValueContainer()
try container.encode(value)
}
}
}
var a: Codable = Optionally<Int>.none
switch a {
case let o as Optional<Any>: // no warning!
if case .none = o {
print("it's none")
}
case let b as Optionally<Any>: // warning: Cast from 'any Codable' (aka 'any Decodable & Encodable') to unrelated type 'Optionally<Any>' always fails
print("it's optionally")
default:
print("not optionally")
}
tera
2
Don't know what's the difference is (between built-in Optional and custom Optionally), but here's a workaround:
protocol OptionallyProtocol {
associatedtype T
var value: T? { get }
}
extension Optionally: OptionallyProtocol {
var value: T? {
switch self {
case .none: return nil
case .value(let v): return v
}
}
}
var a: Codable = Optionally<String>.none
if let v = a as? any OptionallyProtocol {
if let value = v.value {
print("Optionally \(value)")
} else {
print("Optionally none")
}
} else {
print("something else")
}
By no means sure this is the best approach, just something that compiles and seems to be working.
Your question is the new hotness for some reason. 
Thanks for the solution ~