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

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

Related

Enum to map to a comparable key path

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

Using Swift Generics to Call a Non-Generic Library

I'm trying to write a generic Swift wrapper for some of the vector operations in the Accelerate vDSP framework and I'm running into a problem calling the functions in a generic way.
My vector struct looks like:
public struct Vector<T> {
let array: [T]
public static func add(_ a: [T], _ b: [T]) -> [T] {
vDSP.add(a, b)
}
public static func + (_ lhs: Self , _ rhs: Self) -> Self {
Self.add(lhs.array, rhs.array)
}
}
The problem is the add function is overloaded to either take Floats and return Floats or take Doubles and return Doubles. Since the type isn't known at compile time I get an error No exact matches in call to static method 'add'
The only way I've found to get around this is to explicitly check the type before the call and cast:
public static func add(_ a: [T], _ b: [T]) -> [T] {
if T.self is Float.Type {
return vDSP.add(a as! [Float], b as! [Float]) as! [T]
} else {
return vDSP.add(a as! [Double], b as! [Double]) as! [T]
}
}
or to use constrained methods
public static func add(_ a: T, _ b: [T]) -> [T] where T == Float { vDSP.add(a, b) }
public static func add(_ a: T, _ b: [T]) -> [T] where T == Double { vDSP.add(a, b) }
Both of these lead to uncomfortable code duplication, and what's more if I had more than two types (for example if supported is added for the upcoming Float16 type) I'd need to keep adding more and more cases. The latter approach seems especially bad since the method bodies are identical.
I'd like to be able to do something like vDSP.add<T>(a, b) but it seems Swift doesn't support this. Is there some other way to acheive this and avoid the code duplication?

Generic way to do math on protocol extensions

Goal
I want to extend basic types like Int, Double, Float... with more flexible properties and make it presentable in a chart on my app. For example, I made a chart draw that is suitable only for displaying Intbut cannot really display Float. I want to make sure when I pass arguments to this view it will display correctly.
Solution
So I made a protocol (for this example made it like this):
protocol SimplyChartable {
static func max(_ dataSet: [SimplyChartable]) -> SimplyChartable
}
And then make an extension for some types:
extension Int: SimplyChartable { }
extension Double: SimplyChartable { }
extension Float: SimplyChartable { }
and so on ...
Problem
This will be all numeric types, and whenever I pass it as numeric types to a func I need to extend all extension like this:
public static func max(_ dataSet: [SimplyChartable]) -> SimplyChartable {
return (dataSet as? [Int])?.max() ?? 0
}
But for Double func will be identical.
So for min I will end up with similar function, the same for divide, adding , some other math... There is a way to write it once and reuse for every type that extends this protocol?
I found out that:
let dataType = type(of: maxValue) /* where `maxValue` is SimplyChartable*/
Will return original type as rawValue. But output of a method type(of is a Metatype and I cannot return it from function and then add two values of this type. So for example this code will not work:
let val1 = SimplyChartable(4)
let val2 = SimplyChartable(2)
let sum = val1 + val2
And how to make it work not ending up with 3 functions like this:
let val1 = SimplyChartable(4)
let val2 = SimplyChartable(2)
let sum = (val1 as! Int) + (val2 as! Int)
Since they all numeric types why don't you use Comparable?
extension SimplyChartable {
static func max<T: Comparable>(dataSet: [T]) -> T? {
return dataSet.max()
}
static func min<T: Comparable>(dataSet: [T]) -> T? {
return dataSet.min()
}
}
extension Int: SimplyChartable { }
extension Double: SimplyChartable { }
Double.max([1.2, 1.1, 1.3]) // 1.3
Int.min([12, 11, 13]) // 11
Just my two cents worth...
This isn't exactly what you've asked for, since it doesn't let you call a static function directly from a protocol metatype. But since that, AFAIK, isn't possible in Swift currently, perhaps this would be the next best thing?
extension Sequence where Element == SimplyChartable {
func max() -> SimplyChartable {
// put your implementation here
}
}
You can then call this by just:
let arr: [SimplyChartable] = ...
let theMax = arr.max()
For your situation, it's much better to use an Array extension rather than a protocol with an array parameter.
To handle each possible type of array i.e [Int], [Double] or [Float], create a wrapper enum with associated types as follows:
public enum SimplyChartableType {
case int(Int)
case float(Float)
case double(Double)
func getValue() -> NSNumber {
switch self {
case .int(let int):
return NSNumber(value: int)
case .float(let float):
return NSNumber(value: float)
case .double(let double):
return NSNumber(value: double)
}
}
init(int: Int) {
self = SimplyChartableType.int(int)
}
init(float: Float) {
self = SimplyChartableType.float(float)
}
init(double: Double) {
self = SimplyChartableType.double(double)
}
}
You can extend Array as follows:
extension Array where Element == SimplyChartableType {
func max() -> SimplyChartableType {
switch self[0] {
case .int(_):
let arr = self.map({ $0.getValue().intValue })
return SimplyChartableType(int: arr.max()!)
case .double(_):
let arr = self.map({ $0.getValue().doubleValue })
return SimplyChartableType(double: arr.max()!)
case .float(_):
let arr = self.map({ $0.getValue().floatValue })
return SimplyChartableType(float: arr.max()!)
}
}
}
Example usage is:
var array = [SimplyChartableType.double(3),SimplyChartableType.double(2),SimplyChartableType.double(4)]
var max = array.max()
And now it's a lot easier to operate on Int, Double or Float together with:
extension SimplyChartableType: SimplyChartable {
//insert functions here
static func randomFunction() -> SimplyChartableType {
//perform logic here
}
}
The above snippet is good if you need a different functionality which operates on non-Collection types.
This doesn't answer your specific question, unfortunately. Perhaps a work around to use a free function and casting.
import UIKit
protocol SimplyChartable {
func chartableValue() -> Double
}
extension Int: SimplyChartable {
func chartableValue() -> Double {
return Double(self) ?? 0
}
}
extension Double: SimplyChartable {
func chartableValue() -> Double {
return self
}
}
extension Float: SimplyChartable {
func chartableValue() -> Double {
return Double(self) ?? 0
}
}
func maxOfSimplyChartables(_ dataSet: [SimplyChartable]) -> SimplyChartable {
return dataSet.max(by: { (lhs, rhs) -> Bool in
return lhs.chartableValue() < rhs.chartableValue()
}) ?? 0
}
let chartableItem1: SimplyChartable = 1255555.4
let chartableItem2: SimplyChartable = 24422
let chartableItem3: SimplyChartable = 35555
let simplyChartableValues = [chartableItem1, chartableItem2, chartableItem3]
maxOfSimplyChartables(simplyChartableValues)

Unwrapping either one of two types in Swift

I have a method which does exactly the same thing for two types of data in Swift.
To keep things simple (and without duplicating a method) I pass AnyObject as an argument to my method which can be either of these two types. How to I unwrap it with an || (OR) statement so I can proceed? Or maybe this done otherwise?
func myFunc(data:AnyObject) {
if let data = data as? TypeOne {
// This works fine. But I need it to look something like unwrapping below
}
if let data = data as? TypeOne || let data = data as? TypeTwo { // <-- I need something like this
// Do my stuff here, but this doesn't work
}
}
I'm sure this is trivial in Swift, I just can't figure out how to make it work.
You can't unify two different casts of the same thing. You have to keep them separate because they are two different casts to two different types which the compiler needs to treat in two different ways.
var x = "howdy" as AnyObject
// x = 1 as AnyObject
// so x could have an underlying String or Int
switch x {
case let x as String:
print(x)
case let x as Int:
print(x)
default: break
}
You can call the same method from within those two different cases, if you have a way of passing a String or an Int to it; but that's the best you can do.
func printAnything(what:Any) {
print(what)
}
switch x {
case let x as String:
printAnything(x)
case let x as Int:
printAnything(x)
default: break
}
Of course you can ask
if (x is String || x is Int) {
but the problem is that you are no closer to performing an actual cast. The casts will still have to be performed separately.
Building on Clashsoft's comment, I think a protocol is the way to go here. Rather than pass in AnyObject and unwrap, you can represent the needed functionality in a protocol to which both types conform.
This ought to make the code easier to maintain, since you're coding toward specific behaviors rather then specific classes.
I mocked up some code in a playground that shows how this would work.
Hopefully it will be of some help!
protocol ObjectBehavior {
var nickname: String { get set }
}
class TypeOne: ObjectBehavior {
var nickname = "Type One"
}
class TypeTwo: ObjectBehavior {
var nickname = "Type Two"
}
func myFunc(data: ObjectBehavior) -> String {
return data.nickname
}
let object1 = TypeOne()
let object2 = TypeTwo()
println(myFunc(object1))
println(myFunc(object2))
Find if that shared code is exactly the same for both types. If yes:
protocol TypeOneOrTypeTwo {}
extension TypeOneOrTypeTwo {
func thatSharedCode() {
print("Hello, I am instance of \(self.dynamicType).")
}
}
extension TypeOne: TypeOneOrTypeTwo {}
extension TypeTwo: TypeOneOrTypeTwo {}
If not:
protocol TypeOneOrTypeTwo {
func thatSharedMethod()
}
extension TypeOne: TypeOneOrTypeTwo {
func thatSharedMethod() {
// code here:
}
}
extension TypeTwo: TypeOneOrTypeTwo {
func thatSharedMethod() {
// code here:
}
}
And here you go:
func myFunc(data: AnyObject) {
if let data = data as? TypeOneOrTypeTwo {
data.thatSharedCode() // Or `thatSharedMethod()` if your implementation differs for types.
}
}
You mean like this?
enum IntOrString {
case int(value: Int)
case string(value: String)
}
func parseInt(_ str: String) -> IntOrString {
if let intValue = Int(str) {
return IntOrString.int(value: intValue)
}
return IntOrString.string(value: str)
}
switch parseInt("123") {
case .int(let value):
print("int value \(value)")
case .string(let value):
print("string value \(value)")
}
switch parseInt("abc") {
case .int(let value):
print("int value \(value)")
case .string(let value):
print("string value \(value)")
}
output:
int value 123
string value abc

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