1

I'm very new to Swift, but slowly learning by following the Stanford iTunes U course. I have a question about storing and calling functions in an array.

The code I have (below) seems to store the function properly, but when I try to call one of the functions I get this error: '(IntegerLiteralConvertible, IntegerLiteralConvertible) -> $T6' is not identical to (String, Op).

I found this answer that was helpful in getting to where I am, but now I'm stuck.

enum Op {
    case binary((Double, Double) -> Double)
}

var ops = [String: Op]()

func addOperation(symbol: String, op: Op) {
    ops[symbol] = op
}

addOperation("×", Op.binary(*))
addOperation("÷", Op.binary({ $1 / $0 }))
addOperation("+", Op.binary(+))
addOperation("−", Op.binary({ $1 - $0 }))

var newValue = ops["÷"](6, 3) // Produces the error

My understanding was that ops["÷"] should be the function I stored in the array earlier. Am I not calling it properly?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Phil
  • 1,849
  • 4
  • 24
  • 38

2 Answers2

4

@Nate Cook answer is corret but why do you have to use enum in this case? Consider using typealias like following :

var ops = [String: Op]()

    func addOperation(symbol: String, op:Op) {
        ops[symbol] = op
    }

    addOperation("×", (*))
    addOperation("÷", ({ $1 / $0 }))
    addOperation("+", (+))
    addOperation("−", ({ $1 - $0 }))

    var newValue = ops["÷"]?(3,6)

// you have to put this outside of any class
public typealias Op = (Double, Double) -> Double
Zell B.
  • 10,266
  • 3
  • 40
  • 49
  • Sorry, didn't see your post come in! Good idea ;) – Nate Cook Feb 19 '15 at 18:24
  • Is there any advantage to using an enum? – Phil Feb 19 '15 at 18:25
  • 1
    @Phil An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code. In your case enum hold a single value only thats why you should consider using typealias – Zell B. Feb 19 '15 at 18:28
3

You have two problems there. First, subscripting a dictionary returns an optional value, so ops["÷"] is an Op? that needs to be unwrapped before you can use it.

Second, the associated value of an enum can't be accessed directly—you can only get the value when pattern matching in a switch statement. I'd suggest adding a computed property to Op that does the work for you:

enum Op {
    case binary((Double, Double) -> Double)

    var binaryCall: ((Double, Double) -> Double)? {
        switch self {
        case let .binary(operation):
            return operation
        }
    }
}

Then you would call it like this instead:

var newValue = ops["÷"]?.binaryCall?(6, 3)
// Optional(0.5)

An alternate method of implementation would be to just build an dictionary of binary operations, like so (you still need to unwrap once, though):

typealias BinaryOp = (Double, Double) -> Double

var binaryOps: [String: BinaryOp] = [:]

binaryOps["×"] = { $0 * $1 }
binaryOps["÷"] = { $1 / $0 }

newValue = binaryOps["÷"]?(6, 3)
Nate Cook
  • 92,417
  • 32
  • 217
  • 178