Skip to content

Instantly share code, notes, and snippets.

@oliverfoggin
Created October 24, 2021 18:58
Show Gist options
  • Save oliverfoggin/697e9340a5705800adf6ec5ae4cac29d to your computer and use it in GitHub Desktop.
Save oliverfoggin/697e9340a5705800adf6ec5ae4cac29d to your computer and use it in GitHub Desktop.
Trying to recreate the behaviour of Optional...
enum Foo<Wrapped> {
case no
case yes(Wrapped)
}
extension Foo: ExpressibleByNilLiteral {
init(nilLiteral: ()) {
self = .no
}
}
extension Foo {
init(_ value: Wrapped) {
self = .yes(value)
}
}
extension Foo: Equatable where Wrapped: Equatable {
static func ==(lhs: Foo<Wrapped>, rhs: Foo<Wrapped>) -> Bool {
switch (lhs, rhs) {
case let (.yes(l), .yes(r)):
return l == r
case (nil, nil):
return true
default:
return false
}
}
}
@frozen
public struct _OptionalNilComparisonType: ExpressibleByNilLiteral {
/// Create an instance initialized with `nil`.
@_transparent
public init(nilLiteral: ()) {
}
}
extension Foo {
public static func ~=(lhs: _OptionalNilComparisonType, rhs: Foo<Wrapped>) -> Bool {
switch rhs {
case .yes:
return false
case .no:
return true
}
}
public static func ==(lhs: Foo<Wrapped>, rhs: _OptionalNilComparisonType) -> Bool {
switch lhs {
case .yes:
return false
case .no:
return true
}
}
public static func !=(lhs: Foo<Wrapped>, rhs: _OptionalNilComparisonType) -> Bool {
switch lhs {
case .yes:
return true
case .no:
return false
}
}
public static func ==(lhs: _OptionalNilComparisonType, rhs: Foo<Wrapped>) -> Bool {
switch rhs {
case .yes:
return false
case .no:
return true
}
}
public static func !=(lhs: _OptionalNilComparisonType, rhs: Foo<Wrapped>) -> Bool {
switch rhs {
case .yes:
return true
case .no:
return false
}
}
}
extension Foo: Hashable where Wrapped: Hashable {
/// Hashes the essential components of this value by feeding them into the
/// given hasher.
///
/// - Parameter hasher: The hasher to use when combining the components
/// of this instance.
@inlinable
func hash(into hasher: inout Hasher) {
switch self {
case .no:
hasher.combine(0 as UInt8)
case .yes(let wrapped):
hasher.combine(1 as UInt8)
hasher.combine(wrapped)
}
}
}
func ~=<Wrapped>(pattern: Wrapped, value: Foo<Wrapped>) -> Bool where Wrapped: Equatable {
return Foo.yes(pattern) == value
}
enum Bar {
case a
}
//let f: Foo<Bar> = .yes(.a)
let f: Foo<Bar> = nil
switch f {
case nil:
print("Nothing to see here")
case .a:
print("A")
case .no:
print("No")
case .yes(let value):
print(value)
}
@oliverfoggin
Copy link
Author

oliverfoggin commented Oct 25, 2021

@isaac-weisberg not really. You can only get so far. Optional has special privileges built into the compiler that allow it to get around stuff that just isn’t possible for use defined types.

like, you still need to provide .no in the switch even though nil covers that. Etc…

also, the fact that Optional is @Frozen means they don’t have to worry about adding new cases etc…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment