I am implementing result objects using Result, it defines a boxed result like an Optional with an enum:
public enum Result<T, Error>: Printable, DebugPrintable {
case Success(Box<T>)
case Failure(Box<Error>)
...
}
The Equatable protocol defined for Result is as follows:
public func == <T: Equatable, Error: Equatable> (left: Result<T, Error>, right: Result<T, Error>) -> Bool
So, T must conform Equatable.
I would like to be able to have a Success that boxes a Void alike type. But, Void is not Equatable as it's defined as an empty tuple:
typealias Void = ()
The purpose is to be able to have Result types where I do not care about the a value when succeeds.
Is it possible to have an Equatable Void (or no value)?
As quick thoughts, there's the possibility to create an empty struct, but I am looking (if possible) for a more elegant solution.
Why not make Success contain an Optional? (Box<T?> or Box<t>?)?
The you could return nil. The downside is you would be left unwrapping your result
Trying again in Swift 2.0, it seems that Void can be initialized as Void():
public enum Result<T, Error: ErrorType> {
case Success(T)
case Failure(Error)
var value: T? {
switch self {
case .Success(let v):
return v
case .Failure(_):
return nil
}
}
/// Constructs a success wrapping a `value`.
public init(value: T) {
self = .Success(value)
}
/// Constructs a failure wrapping an `error`.
public init(error: Error) {
self = .Failure(error)
}
}
enum MyError: ErrorType {
case AnError
}
let result = Result<Void, MyError>(value: Void())
let success = result.value != nil // returns true
let error = result.value == nil // returns false
My solution to this issue is as you suggest to make a new struct that contains no members. I'll post it here for others who need a working solution.
Make it Decodable and Equatable. Now you can treat "Void" like a real type. You can just map to this value wherever you need it or map back out.
typealias VoidDecodableResult = ((Result<VoidDecodable, Error>) -> Void)
struct VoidDecodable: Decodable, Equatable {}
One thing is in your success block in a generic function you can just try to cast to VoidDecodable and return an instance.
if T.self is VoidDecodable.Type {
completion(.success(VoidDecodable() as! T))
return
}
Add a helper to make mapping out easier:
struct VoidDecodable: Decodable, Equatable {
var orVoid: Void {
()
}
}
Related
I'm writing some code where a user can select how a particular array of data is sorted. I was trying to see if I could hold the set of permissible sort properties in an enum. What I want to be able to express is something like:
import Foundation
struct MyStruct {
let a: Int
let b: Int
}
enum MyStructProps {
case a, b
func comparableKeyPath<T: Comparable>() -> KeyPath<MyStruct, T> {
switch self {
case .a: return \MyStruct.a
case .b: return \MyStruct.b
}
}
}
At the moment each case returns a compiler error: key path value type 'Int' cannot be converted to contextual type 'T'.
Looking at the post Swift Generics, Constraints, and KeyPaths I would need to embed this within a sort function, so that Swift knows how to derive the type of the generic key path.
But I was curious to learn if there is a way of returning a generic keypath in my naive code?
If you need to work at some more intermediate level than the following, you'll need to type-erase, as Sweeper says in the comment.
Otherwise, because you can't return different types from one function, just employ generics for the intermediate steps, and have one function at the end of the process that employs multiple types.
extension Sequence where Element == MyStruct {
func sorted(by property: Element.ComparableProperty) -> [Element] {
switch property {
case .a: return sorted(by: \.a)
case .b: return sorted(by: \.b)
}
}
}
extension MyStruct {
enum ComparableProperty {
case a, b
}
}
public extension Sequence {
/// Sorted by a common `Comparable` value.
func sorted<Comparable: Swift.Comparable>(
by comparable: (Element) throws -> Comparable
) rethrows -> [Element] {
try sorted(by: comparable, <)
}
/// Sorted by a common `Comparable` value, and sorting closure.
func sorted<Comparable: Swift.Comparable>(
by comparable: (Element) throws -> Comparable,
_ areInIncreasingOrder: (Comparable, Comparable) throws -> Bool
) rethrows -> [Element] {
try sorted {
try areInIncreasingOrder(comparable($0), comparable($1))
}
}
}
I know an enum can have a closure as an associated value, such as:
enum SomeEnum {
case closureOne (String, Double -> Double)
case closureTwo (String, (Double, Double) -> Double)
}
But, can an enum have a closure as a raw value? For instance, does something like this work?
enum someEnum: () -> Void {
case closureOne = doSomething
case closureTwo = doSomethingElse
}
where
let doSomething = {
// Do something here.
}
let doSomethingElse {
// Do something else here.
}
It's not as straight forward, but you could use OptionSet, see this page:
Unlike enumerations, option sets provide a nonfailable init(rawValue:) initializer to convert from a raw value, because option sets donβt have an enumerated list of all possible cases. Option set values have a one-to-one correspondence with their associated raw values.
Could be something like this:
func doSomething() {}
func doSomethingElse() {}
struct MyClosures: OptionSet {
static let closureOne = MyClosures(rawValue: doSomething)
static let closureTwo = MyClosures(rawValue: doSomethingElse)
let rawValue: () -> Void
init(rawValue: #escaping () -> Void) {
self.rawValue = rawValue
}
init() {
rawValue = {}
}
mutating func formUnion(_ other: __owned MyClosures) {
// whatever makes sense for your case
}
mutating func formIntersection(_ other: MyClosures) {
// whatever makes sense for your case
}
mutating func formSymmetricDifference(_ other: __owned MyClosures) {
// whatever makes sense for your case
}
static func == (lhs: MyClosures, rhs: MyClosures) -> Bool {
// whatever makes sense for your case
return false
}
}
And so you can use it as:
let myClosures: MyClosures = [ .closureOne, .closureTwo ]
HOWEVER looking at your explanation in the comment:
So I'm trying to find the most efficient way to run a function given the state of a variable.
I think what you actually want is some sort of state machine. Some examples are available here and here
I have a plain Result type:
public enum Result<T> {
case success(T)
case error
}
I want to make the type Equatable, easy enough:
public enum Result<T: Equatable>: Equatable {
case success(T)
case error
// definition of ==
}
But then I want to use Result<Void>, and thatβs a type error since Void doesnβt conform to Equatable. Is there a way to define a Result type that would conform to Equatable, accept Result<Void> and still use the correct equality check for T: Equatable? Wouldnβt it make sense for Void to implement Equatable?
I don't think that is possible at present. Void is the type of the
empty tuple (), and tuples cannot adopt protocols (a discussion about
that topic starts at [swift-evolution] Synthesizing Equatable, Hashable, and Comparable for tuple types).
A possible workaround (as suggested by #Hamish above) is to use a custom
type instead of Void:
struct Unit: Equatable {
static var unit = Unit()
public static func ==(lhs: Unit, rhs: Unit) -> Bool {
return true
}
}
let res = Result.success(Unit.unit)
I initially though that once SE-0143 Conditional conformances is implemented then one could define
public enum Result<T> {
case success(T)
case error
}
public extension Result: Equatable where T: Equatable {
public static func ==(lhs: Result, rhs: Result) -> Bool {
// ...
}
}
public extension Result: Equatable where T == Void {
public static func ==(lhs: Result, rhs: Result) -> Bool {
return true
}
}
without the need the make Void itself Equatable.
However (again attribution goes to #Hamish) this won't work
because multiple conformances won't be permitted.
I have this result datatype called π which wraps a type and a progress
public enum π<T> {
case Success(T)
case Progress(CGFloat)
}
class func rx_request(router: Router) -> Observable<π<AnyObject>>
This AnyObject needs to be transformed into a Mappable structure (ObjectMapper), so because I have several of these Mappable structs, I wanted to achieve something like this, a generic map that I can use:
class func rx_convert<T : Mappable>(value: π<AnyObject>) -> Observable<π<T>> {
return Observable.create { observer in
switch value {
case .Success(let object):
guard let convertedObject = Mapper<T>().map(object) else {
observer.onError(NetworkError.IncorrectDataReturned)
return NopDisposable.instance
}
observer.on(.Next(π<T>.Success(convertedObject)))
observer.on(.Completed)
case .Progress(let progress):
observer.on(.Next(π<T>.Progress(progress)))
break
}
return NopDisposable.instance
}
}
It seems the above definition is wrong because this cannot be compiled: Cannot explicitly specialize a generic function
.flatMapLatest({ _ in
π―.rx_request(Router.Pipeline)
})
.flatMapLatest({ result -> Observable<π<ResponsePipeline>> in
π―.rx_convert<ResponsePipeline>(result)
// Cannot explicitly specialize a generic function
})
What am I doing wrong here?
.flatMapLatest({ result -> Observable<π<ResponsePipeline>> in
return π―.rx_convert(result)
})
Because the closure passed to flatMapLatest is already typed to return an Observable<π<ResponsePipeline>>, compiler can infer the type for rx_convert to be π<AnyObject> -> Observable<π<ResponsePipeline>> so you can drop <ResponsePipeline> from the call.
I'm using the antitypical/result package to provide a generic Result type. This package defines Result as follows:
public enum Result<T, Error> {
...
}
Now, I only wish to return errors of type NSError in my code, so it would be nice if I didn't have to keep doing things this:
func myFunc() -> Result<String, NSError> { ... }
Instead, I want to create a derived StdResult type so that I can do this instead:
func myFunc() -> StdResult<String> { ... }
I've tried various things but I can't find a solution. This, for example, doesn't work:
typealias StdResult<T> = Result<T, NSError>
Is there a solution which will work?
Unfortunately we're pretty limited here. Swift doesn't support generic typealias, so we can do this as a sort of hack with struct:
struct StdResult<T> {
typealias Type = Test<T, NSError>
}
func myFunc() -> StdResult<String>.Type {
}
Does that fit what you were looking for closely enough?
At the moment, there's no generic typealias support nor enumeration inheritance, but you could use RawRepresentable protocol. It's not as easy as if a generic typealias exists, but it may fit your needs.
RawRepresentable
From Apple's documentation:
A type that can be converted to an associated "raw" type, then converted back to produce an instance equivalent to the original.
public protocol RawRepresentable {
typealias RawValue
public init?(rawValue: Self.RawValue)
public var rawValue: Self.RawValue { get }
}
That said, your raw value must be Result<T, NSError>:
enum StdResult<T>: RawRepresentable {
var rawValue: Result<T, NSError> {
switch self {
case .Success(let value):
return Result.Success(value)
case .Failure(let error):
return Result.Failure(error)
}
}
init?(rawValue: Result<T, NSError>) {
switch rawValue {
case .Success(let value):
self = .Success(value)
case .Failure(let error):
self = .Failure(error)
}
}
case Success(T)
case Failure(NSError)
}
func myFunc() -> StdResult<String> { }
Note: Properties and methods of original Result enumeration are only accessible from rawValue property, so, for example, if you want to compare your new StdResult with another, you must use rawValue property or reimplement these protocols yourself.
You could alias the specific Result type so you don't have to constantly do func myThing() -> Result<String, NSError>
e.g.
typealias StringResult = Result<String, NSError>
func myOtherThing() -> StringResult
It's more difficult for me to come up with a generic solution like
MyResult<String>
without understanding exactly what Result is doing. I could take another crack at it if you post some of the internals.