Skip to content

Instantly share code, notes, and snippets.

@ruslangazizov
Last active September 24, 2022 18:01
Show Gist options
  • Select an option

  • Save ruslangazizov/b742f4bcd7f3bf8b7feed01c076e1408 to your computer and use it in GitHub Desktop.

Select an option

Save ruslangazizov/b742f4bcd7f3bf8b7feed01c076e1408 to your computer and use it in GitHub Desktop.
Custom implementation of swift's Optional enum
enum CustomOptional<Wrapped> {
case none
case some(Wrapped)
public init(_ some: Wrapped) {
self = .some(some)
}
func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> CustomOptional<U> {
switch self {
case .none:
return .none
case .some(let wrapped):
do {
let transformed = try transform(wrapped)
return .some(transformed)
} catch let error {
throw error
}
}
}
func flatMap<U>(_ transform: (Wrapped) throws -> CustomOptional<U>) rethrows -> CustomOptional<U> {
switch self {
case .none:
return .none
case .some(let wrapped):
do {
let transformed = try transform(wrapped)
return transformed
} catch let error {
throw error
}
}
}
}
extension CustomOptional: ExpressibleByNilLiteral {
public init(nilLiteral: ()) {
self = .none
}
}
extension CustomOptional: CustomStringConvertible {
public var description: String {
switch self {
case .none:
return "nil"
case .some(let wrapped):
var wrappedDescription: String = "\(wrapped)"
if wrapped is String {
wrappedDescription = "\"\(wrappedDescription)\""
}
return "CustomOptional(\(wrappedDescription))"
}
}
}
extension CustomOptional {
static func ?? (lhs: Self, rhs: Self) -> Self {
switch (lhs, rhs) {
case (.none, .none):
return .none
case (.some(let value), _):
return .some(value)
case (.none, .some(let value)):
return .some(value)
}
}
static func ?? (lhs: Self, rhs: Wrapped) -> Wrapped {
switch lhs {
case .none:
return rhs
case .some(let value):
return value
}
}
}
extension CustomOptional: Equatable where Wrapped: Equatable {
static func == (lhs: Self, rhs: @autoclosure () -> Wrapped) -> Bool {
switch lhs {
case .none:
return false
case .some(let value):
return value == rhs()
}
}
static func == (lhs: @autoclosure () -> Wrapped, rhs: Self) -> Bool {
return rhs == lhs()
}
}
extension String {
func toInt() -> CustomOptional<Int> {
if let number = Int(self) {
return .some(number)
} else {
return .none
}
}
}
let someInteger = CustomOptional(1)
print(someInteger) // CustomOptional(1)
let stringNumber = someInteger.map { "\($0)" }
print(stringNumber) // CustomOptional("1")
print(stringNumber.map { $0.toInt() }) // CustomOptional(CustomOptional(1))
print(stringNumber.flatMap { $0.toInt() }) // CustomOptional(1)
let optionalInt: CustomOptional<Int> = nil
let anotherOptionalInt = CustomOptional(9)
let unwrappedInt = optionalInt ?? anotherOptionalInt ?? 5
print(optionalInt == anotherOptionalInt) // false
print(optionalInt == unwrappedInt) // false
print(unwrappedInt == optionalInt) // false
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment