Recursive Swift Either Enum with Generic Associated Values - ios

I want to develop a recursive Either type as a Swift enum (at least a partially working version (;), and so have been playing around with generics (trying to work with the type system).
Here is what I have so far:
enum NumericEitherEnum<Left, Right> {
case left(Left)
case right(Right)
var left: Left? {
switch self {
case .left(let leftie) where leftie is NumericEitherEnum<Int, Float>:
return (leftie as? NumericEitherEnum<Int, Float>)?.left // This won't work (obviously)
case .left(let left):
return left
case .right(_):
return nil
}
}
var right: Right? {
switch self {
case .left(_):
return nil
case .right(let right) where right is NumericEitherEnum:
return (right as? NumericEitherEnum)?.right // This assumes the generic parameters of Left, Right in the current enum so won't work.
case .right(let right):
return right
}
}
}
I get cryptic diagnostic error messages in Xcode, which I haven't been able to get around:
'Replace (leftie as? NumericEitherEnum<Int, Float>)? with NumericEitherEnum<Int, Float>'
'Enum case 'left' cannot be used as an instance member'
What I am trying to achieve:
print(NumericEitherEnum<NumericEitherEnum<Int, Float>, NumericEitherEnum<Int, Float>>.left(.left(3)).left ?? "failed :(") // Parses the innermost value 3
The fix-it doesn't fix the error or advise how to actually address the underlying cause. I think this is probably an edge case for the compiler to parse (maybe even bug) ;). I also realise that in fact it doesn't make sense logically to return an Int for a Left? type but is there any way I can express this within the type system (I tried associated types but I still don't know how to make this dynamic). There's also a problem to handle nested enums that have a different generic type signature (not sure how to express this).
How can I resolve this issue in a better way? Ideally, I want to have a clean call site without too much indirection and extra data structures but would be open to trying out a different data structure if this isn't practically achievable.

So I discovered that Swift 2 introduced support for recursive enums ages ago - source! While this is great, I didn't manage to find any SO questions for this specific problem i.e. Generic Recursive Enums that had also been answered (here). I will summarise the final (partial solution) code now.
It turns out that I needed to describe what the problem is in terms of data structures. Essentially we want .left to contain either a value of type Left or a RecursiveEither<Left, Right>. With this simple idea, we can create two enums - one for the wrapper enum, and one for the nested enum which can take a Value or another wrapper.
enum RecursiveEither<Left, Right> {
case left(ValueOrLeftOrRight<Left, Left, Right>)
case right(ValueOrLeftOrRight<Right, Left, Right>)
var left: Left? {
guard case .left(let leftie) = self else { return nil }
return leftie.left
}
var right: Right? {
guard case .right(let rightie) = self else { return nil }
return rightie.right
}
}
enum ValueOrLeftOrRight<Value, Left, Right> {
case value(Value)
indirect case left(ValueOrLeftOrRight<Left, Left, Right>)
indirect case right(ValueOrLeftOrRight<Right, Left, Right>)
var left: Left? {
switch self {
case .value(let left): return left as? Left
case .left(let content): return content.left
default: return nil
}
}
var right: Right? {
switch self {
case .value(let right): return right as? Right
case .right(let content): return content.right
default: return nil
}
}
}
The call site is nice with this design:
let e = RecursiveEither<Int, Int>.left(.left(.left(.left(.value(3)))))
That being said, there are still limitations to this answer - assuming Left and Right won't change even in nested Either. Also, it's possible to design this differently with only one indirect case to wrap the Either type in another associated value - that might be more memory efficient since fewer frames get pushed onto the call stack at runtime.
I have posted a gist with attempts on this problem.
If anyone has suggestions to improve this implementation, feel free to add to this.

Related

Using ParseSwift .query().find() in an iOS app

When using ParseSwift in an iOS app, I have the following kind of code working:
do {MyCollection.query().find() {
result in
switch result {
case .success(let items):
... useful work here ...
case .failure(let error):
print("Error in \(#function): \(error)")
}
}
}
I need to see some sample code where the query().find() part is more selective. For some reasons, what I have tried on my own has always failed at this point. I must surely be missing some very simple detail, but I hope a few examples will make things more obvious.
I have looked at this document. But there is no example of this type:
MyCollection.query().find()
I can't even see a case using find(). And the syntax used for the selection within the query(): query("score" > 9), isn't working when I want to use it, for some reason.
For example I want do something like the following, parameter is provided by the context and field is a field inside MyCollection pointing to another collection :
do {MyCollection.query("field" == parameter).find() {
......
}
And though the above isn't working. I can still do something like the following:
do {MyCollection.query().find() {
result in
switch result {
case .success(let items):
for item in items {
if item.field?.objectId != parameter {continue} // Eliminate useless item !
// Keep item for useful work.
......
}
So performing the selection I want, but in a very inefficient manner, since I am getting the complete collection when I don't need it.

Swift enum with custom object raw value

I try to implement a state machine for my ViewController, so i create a enum to express the possible state of my ViewController :
enum SMState:RawRepresentable{
case empty,data(UIView),failed(UIView),noData(UIView)
}
The 4 state of enum is suitable for my ViewController, and some state associate with a custom view to show when ViewController enter the specify state.
Then i make SMState impl RawRepresentable Protocol
enum SMState:RawRepresentable{
case empty,data(UIView),failed(UIView),noData(UIView)
typealias RawValue = UIView
init?(rawValue: SMState.RawValue) {
// rawValue is a view but i can't judge what to return
return what???
}
var rawValue: UIView{
switch self {
case .data(let v):
return v
case .failed(let v):
return v
case .noData(let v):
return v
case .empty:
return UIView()
}
}
}
How should i implement init?(rawValue:SMState.RawValue) function above, i can't image how to do this.
Update
Why i implement RawRepresentable :
I think enum is more suitable for representable different state for ViewController instead of Class or Struct, but enum cannot contains stored property, it can only carry a UIView Object through RawRepresentable, any better idea or magic is welcome :D
#Hamish You are right, i shouldn't insist using RawRepresentable, after a nice sleep, i finally archive what i want :
//: Playground - noun: a place where people can play
import UIKit
enum SMState{
case empty,data(UIView),failed(UIView),noData(UIView)
}
extension SMState{
init() {
self = .empty
}
init(failed view:UIView) {
self = .failed(view)
}
init(data view:UIView) {
self = .data(view)
}
init(noData view:UIView) {
self = .noData(view)
}
}
let state = SMState(failed: UIView())
switch state {
case .failed(let v):
print(v)
default:break
}
This is what i want, each enum state own a separate View, i do different operation in different state, using the View that the state carry ~
This approach is much like using Class, in my situation, i am not sure that there may be more states, then it is impossible to extend or subclass the SMState because its a enum, i am think about using Class
What i am trying to do is much like this library StatefulViewController, and i want to make it more flexible.
Any suggestion is welcome ~
:D
There is already available a specific state machine you could use instead of inventing the wheels: GKStateMachine. It has all the required method to transition from state to state. We also use it for different view controller states. Just take you time to read a bit and find some examples, to have your code nice and clean. You will also be able to combine the implementation with a corresponding enum of states, which will just define the states without a need of having associated values there.

Is it possible to add a case to an existing enumeration where there is no source?

I am implementing my own TableView because I would like to have special animation when reloading a row using reloadRowsAtIndexPaths:withRowAnimation.
The problem is that I need to give a type of animation when I'm calling this method. So I would like to know if it's possible to add an extra case to UITableViewRowAnimation enumeration?
No, it's not possible, for at least one reason: switch statements not using a default case wouldn't compile, because they would be missing the newly added case.
Consider this enum:
enum TestEnum {
case ONE
case TWO
}
and some code using it:
let testOne = TestEnum.ONE
switch testOne {
case .ONE:
println("one")
case .TWO:
println("two")
}
If you were able to add one or more cases in an extension:
extension TestEnum {
case THREE
}
then the switch statement written above wouldn't compile because the new case is not handled.

run function depending on passed integer in swift

I want to run different functions depending on selected level Integer
so if selected level is 1 then runfunc1(), if 2 then runfunc2()...
I know this is possible using if else
if levelselected == 1 {
runfunc1()
} else if levelseletecd == 2 {
runfunc2()
// ... and so on
}
Is there any better way than this, perhaps something like this
runfunc%i(),levelselected // I know its not correct but something similar
I dont want to write new code for every level, so any better way?
You can use something like:
var levelSelected = 0 //
var selector = Selector("runFunc\(levelSelected)")
if self.respondsToSelector(selector) {
NSThread.detachNewThreadSelector(selector, toTarget: self, withObject: nil)
}
You could have an array or dictionary of functions. A dictionary might be nicer since the logic for checking if the level is valid is a lot simpler:
let funcs = [1: runfunc1, 2: runfunc2]
if let funcToRun = funcs[levelselected] {
funcToRun()
}
However, you won't be able to easily dynamically build a function name from strings and numbers without using #objc functionality.
(except in the sense that you could make the key to the dictionary a string of the function name, but you still have to build the dictionary using actual function names determined at compile time)
That said, you can add to the funcs variable from elsewhere in the code so it does mean to can "hook up" new levels without changing this dispatching logic.
Not the exact solution you are looking for but this can make it easier :
Declare an array of the desired functions:
var levelFunctions: [()->()] = [runfunc1, runfunc2, runfunc3]
This syntax declares an array of functions that have zero argument and return nothing. You initialize this array with the required function names and then execute the desired function using the levelselected variable:
levelFunctions[levelselected]() // Or levelselected-1 if the variable is not zero-based
EDIT:
As Airspeed Velocity mentioned in the comment and his answer you should make sure the level is in the array bounds.
I prefer to create a function, for example runFuncFromLevel::Int -> (() -> Void). runFuncFromLevel return a proper function that you need.
func runFuncFromLevel(level: Int) -> () -> Void
{
switch level
{
case 1: return runfunc1
case 2: return runfunc2
default: return {}
}
}

Why do I need to unwrap this variable?

import SpriteKit
let NumOrientations: UInt32 = 4
enum Orientation: Int, Printable {
case Zero = 0, Ninety, OneEighty, TwoSeventy
var description: String {
switch self {
case .Zero:
return "0"
case .Ninety:
return "90"
case .OneEighty:
return "180"
case .TwoSeventy:
return "270"
}
}
static func random() -> Orientation {
return Orientation(rawValue: Int(arc4random_uniform(NumOrientations)))!
}
}
I am new to swift, but I have a lot of programming experience. However, I've never encountered anything like the variable "wrapping" when dealing with unknowns in Swift.
I have the static function random, which returns an Orientation. There is NOTHING optional about the Orientation class. However, I have to use an exclamation point on the return statement in the random function.
Why is this? Excuse my complete lack of knowledge about swift.
Well, obviously the initializer can fail. Let's assume:
Orientation(rawValue: 10)
This won't find a value in your enum, so what do you expect it to return? It will return nil. That means the return value must be an optional because nil can be returned.
This is explicitly mentioned in Swift Language Guide, Enumerations, Initializing from a Raw Value:
NOTE
The raw value initializer is a failable initializer, because not every raw value will return an enumeration member. For more information, see Failable Initializers.
However, in this case (method random) you are sure that a nil won't be returned, so the best solution is to unwrap the optional before returning it from random.

Resources