Socrates
Socrates

Reputation: 41

Swift - Enum Returning The Wrong Value Type

I am having issues with the following code:

private enum Op : Printable {
    case Operand(Double)
    case Constant(String, Double)
    case Variable(String)
    case UnaryOperation(String, Double -> Double)
    case BinaryOperation(String, (Double, Double) -> Double)
    var description: String {
        get {
            switch self {
            case .Operand(let operand):
                return "\(operand)"
            case .Constant(let constant, _):
                return constant
            case .Variable(let variable):
                return variable
            case .UnaryOperation(let symbol, _):
                return symbol
            case .BinaryOperation(let symbol, _):
                return symbol
            }
        }
    }
}

private var knownOps = [String:Op]()

init() {
    func learnOp(op: Op) {
        knownOps[op.description] = op
    }
    learnOp(Op.Constant("π", M_PI))
    learnOp(Op.UnaryOperation("√", sqrt))
    learnOp(Op.UnaryOperation("sin", sin))
    learnOp(Op.UnaryOperation("cos", cos))
    learnOp(Op.UnaryOperation("±") { -1 * $0 })
    learnOp(Op.BinaryOperation("×", *))
    learnOp(Op.BinaryOperation("÷") { $1 / $0 })
    learnOp(Op.BinaryOperation("+", +))
    learnOp(Op.BinaryOperation("-") { $1 - $0 })
}

After the init() is complete, the dictionary knownOps contains the following:

knownOps    [String : Calculator.CalculatorModel.Op]    9 key/value pairs   
[0] _DictionaryElement<String, Calculator.CalculatorModel.Op>       
key String  "×" 
value   Calculator.CalculatorModel.Op   Operand Operand
[1] _DictionaryElement<String, Calculator.CalculatorModel.Op>       
key String  "+" 
value   Calculator.CalculatorModel.Op   Operand Operand
[2] _DictionaryElement<String, Calculator.CalculatorModel.Op>       
key String  "÷" 
value   Calculator.CalculatorModel.Op   Operand Operand
[3] _DictionaryElement<String, Calculator.CalculatorModel.Op>       
key String  "π" 
value   Calculator.CalculatorModel.Op   Constant    Constant
[4] _DictionaryElement<String, Calculator.CalculatorModel.Op>       
key String  "-" 
value   Calculator.CalculatorModel.Op   Operand Operand
[5] _DictionaryElement<String, Calculator.CalculatorModel.Op>       
key String  "±" 
value   Calculator.CalculatorModel.Op   UnaryOperation  UnaryOperation
[6] _DictionaryElement<String, Calculator.CalculatorModel.Op>       
key String  "sin"   
value   Calculator.CalculatorModel.Op   UnaryOperation  UnaryOperation
[7] _DictionaryElement<String, Calculator.CalculatorModel.Op>       
key String  "√" 
value   Calculator.CalculatorModel.Op   UnaryOperation  UnaryOperation
[8] _DictionaryElement<String, Calculator.CalculatorModel.Op>       
key String  "cos"   
value   Calculator.CalculatorModel.Op   UnaryOperation  UnaryOperation

My question is: why are the binaryOperations being captured as Operands in the dictionary?

Upvotes: 4

Views: 716

Answers (2)

0x416e746f6e
0x416e746f6e

Reputation: 10136

Ok, I think I managed to reproduce what you say in your question. If I run the thing in debug mode in Xcode 6.4, put a breakpoint, and inspect the contents of knownOps, then indeed I see binary operations stored as just an operand.

What I think is happening is Swift compiler optimisation coupled with a bug.

Reasons I think so are:

  • Similar code (just ported) to Xcode 7 beta renders enum in knownOps as Invalid.
  • If I "inspect" contents of knownOps by printing them out (e.g. in a for-loop) then everything is printed out just as expected, both in Xcode 6.4 and in Xcode 7 beta.
  • If I trace the execution of code that prints out the contents of knownOps by stepping into instructions, then I do not see anything that looks like: 1) check out the value stored by enum property, and then 2) based on property's value, decide what to return as description computed property of the enum.

Therefore, most likely your code is simple enough for the compiler to be able to "predict" what has to be printed out or what the execution path should look like, to just throw all "unnecessary" stuff out. And probably the debugger in 6.4 is simply not up to speed with this thing..

But good news is that debugger from Xcode 7 "knows" about this. It says invalid instead of feeding you with a bogus.

Upvotes: 1

mbottone
mbottone

Reputation: 1235

I added the following variable to your enum:

var type: String {
    get {
        switch self {
        case .Operand:
            return "Operand"
        case .Constant:
            return "Constant"
        case .Variable:
            return "Variable"
        case .UnaryOperation:
            return "UnaryOperation"
        case .BinaryOperation:
            return "BinaryOperation"
        }
    }
}

Then looped through the dict with the following code:

for (key, value) in knownOps
{
    let valueType = value.type
    println("\(key) : \(valueType)")
}

This gave me the output:

× : BinaryOperation
+ : BinaryOperation
÷ : BinaryOperation
π : Constant
- : BinaryOperation
± : UniaryOperation
sin : UniaryOperation
√ : UniaryOperation
cos : UniaryOperation

So I guess the answer to your questions is that it isn't. I can't offer an answer as to why the debugger or whatever you used to inspect the values was incorrect, but the code you posted isn't wrong.

Upvotes: 1

Related Questions