Enum to map to a comparable key path - swift

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))
}
}
}

Related

Can a Swift enum have a function/closure as a raw value?

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

Generic-type extension with a new generic type in Swift

I'd like to extend the generic type Array<Element> with a constraint on Element that depends on another generic type, such as Element == Optional<Wrapped>.
In the case where Element is not generic, it is easy:
extension Array where Element == String {
func merge() -> String { ... }
}
I tried the following, but the compiler does not accept it.
extension Array<Wrapped> where Element == Optional<Wrapped> {
func merge() -> Optional<Wrapped> { ... }
}
What syntax should I use in this case?
Thanks in advance!
You can put a constraint on the method instead:
extension Array {
func merge<T>() -> T? where Element == T? {
// ...
}
}

Cannot convert value of type 'Result<Data, Error>' to closure result type 'Result<T, E>'

I need help with generics and return types after conversion of older (not mine) code from swift 2 to swift 4
let cryptedJsonData = packet.encodeJSON()
.flatMap { $0.gzippedData() } //here I am getting error
Cannot convert value of type 'Result<Data, Error>' to closure result type 'Result<T, E>'
flatmap function
extension Result {
func map<U>( _ function: #escaping (T) -> U ) -> Result<U, E> {
return flatMap { .success( function( $0 ) ) }
}
func flatMap<U>( _ function: (T) -> Result<U, E> ) -> Result<U, E> {
switch self {
case .success(let value): return function(value)
case .failure(let error): return .failure(error)
}
}
}
gzippedData()
private let CHUNK_SIZE: Int = 2 ^ 14
func gzippedData() -> Result<Data, Error> {
var data = Data(count: CHUNK_SIZE)
return .success( data as Data)
}
Result
enum Result<T, E> {
case success(T)
case failure(E)
}
If you defined your own Result type, I suspect the problem stems from a type incompatibility between two definitions of Result in different modules.
Note that there is a Result type already defined in the Swift's standard library (see https://developer.apple.com/documentation/swift/result), whose implementation is pretty close to what you've posted. If you actually defined your own type, it is then possible that the Result returned by encodeJSON() differ from the Result returned by gzippedData(). Unfortunately, Swift handles clashing names very poorly, especially when those occur with names from the standard library.
Here's a way to replicate your problem:
// This enum is defined in my own source.
enum Result<T, E> {
case success(T)
case failure(E)
}
// This is an dummy error type, with the sole purpose of specializing `Result`.
enum SomeError: Error {}
// This extension has for sole purpose to add a method to `String` that returns
// an instance of *my* `Result` type.
extension String {
func foo() -> Result<String, SomeError> {
return .success(self)
}
}
// Now assume this function comes from a third party library that uses Swift's
// `Result` type, from the standard library.
func bar() -> Swift.Result<String, SomeError> {
return .success("Hello, World!")
}
// The following line will trigger the exact same error as yours, because the
// `Result` type that expects `flatMap`'s argument is not *my* `Result` type,
// but that of Swift's standard library.
bar().flatMap { $0.foo() }
Notice that this example will compile just fine if you replace Swift.Result by simply Result on bar's codomain (assuming you also provide a definition for flatMap).
If you defined your own Result type, I suggest you either use Swift's one, which I guess behaves exactly as you intended, or rename your own so that its definition no longer clashes with that in Swift's standard library.

Implement an Equatable Void (None) type

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 {
()
}
}

Write a custom access operator in Swift

I implemented a helper to have an array of unowned references:
class Unowned<T: AnyObject>
{
unowned var value : T
init (value: T) { self.value = value }
func get() -> T { return self.value }
}
Now, it is possible to do [ Unowned<Foo> ]. However, I'm not satisfied with having the additional get() method to retrieve the underlying object. So, I wanted to write a custom binary operator, e.g. --> for being able to do
for unownedFoo in ArrayOfUnownedFoos
{
var bar : Int = unownedFoo-->method()
}
My current approach is to define
infix operator --> { }
func --><T> (inout lhs: Unowned<T>, inout rhs: () -> Int) -> Int
{
}
The idea I had behind this is:
lhs is obvisouly the object I get out of the array, on which I want to perform the call on
rhs is the method I desire to call. In this case method() would not take no parameters and return an Int, and therefore
The return value is int.
However, the following problems / uncertainties arise:
Is this the correct approach?
Are my assumptions above correct?
How can I call the provided closure rhs on the instance of the extracted Unowned<T>, e.g. (pseudocode) lhs.value.rhs(). If method() was static, I could do T.method(lhs.value), but then I would have to extract the name of the method somehow to make it more generic.
Maybe, a postfix operator is rather simple.
postfix operator * {}
postfix func *<T>(v:Unowned<T>) -> T {
return v.value
}
// Usage:
for unownedFoo in ArrayOfUnownedFoos {
var bar : Int = unownedFoo*.method()
}
Use something like:
func --> <T:AnyObject, V> (lhs: Unowned<T>, rhs: (T) -> V) -> V
{
return rhs (lhs.get())
}
and then use it as:
for unownedFoo in ArrayOfUnownedFoos
{
var bar : Int = unownedFoo-->{ (val:Int) in return 2*val }
}
Specifically, you don't want to use method() as that itself is a function call - which you probably don't want unless method() is actually returning a closure.