rodalfus rodalfus - 6 months ago 31
iOS Question

Segmentation Fault 11 when compiling swift file with enum in Xcode

When trying to compile a Swift file such as this one (as part of a project), Xcode (Version 7.3.1) throws a segmentation fault 11

while emitting SIL for 'operationForOperationType'


import Foundation

enum OperationType: String{
case Addition = "∑"

func operationForOperationType() -> ([Double], [[Double]]? -> Double){
switch self {
case OperationType.Addition:
return {$0.reduce(0, combine: {$0 + $1})}
}
}
}


Is this a compiler bug or actually the result of the given code? Other variations of the code (more than one case, switch on a given
OperationType
instead of
self
) also resulted in a segmentation fault 11.

Edit: Remove .output (a copy-paste-error)

Edit II: The function's purpose is to return a closure for a given
OperationType
. For example, if my
OperationType
is addition, I want it to return the closure that adds elements in the array. This, of course, is a simplification. It might occur, that I want a closure to be returned, which combines elements in the array and a two dimensional array (think matrix multiplication).

Usage may be, for example:

var op = OperationType.Addition
let f = op.operationForOperationType()
let arr: [Double] = [1, 5, 2]
f(arr, nil)
//-> 8

Answer

First off: if the compiler is crashing you might want to submit a bug report to apple.

Secondly regarding your code: Took me a while to figure out what is wrong here! Your declared return type is not a closure!

func operationForOperationType() -> ([Double], [[Double]]? -> Double) {

This line means the function returns a tuple of one [Double] and one closure of type [[Double]]? -> Double. It does not return a closure whose inputs are [Double] and [[Double]]? and returns a Double.

To correct the return type to actually specify to return just a closure you have to write:

func operationForOperationType() -> ([Double], [[Double]]?) -> Double {

Note the moved closing )!

Now we can get to the actual implementation of the return value:

func operationForOperationType() -> ([Double], [[Double]]?) -> Double {
    switch self {
    case OperationType.Addition:
        return { (a, b) in a.reduce(0, combine: {$0 + $1})}
    }
}

Since we defined the input to be of type ([Double], [[Double]]?), a tuple, we have to either access those parameters via $0.0 and $0.1 or we write (a, b) in to map the first tuple value to a and the second to b.

Now everything compiles. I still do not know what you want to do with b, but that is none on my business ;)

Putting it all together:

enum OperationType: String{
    case Addition = "∑"

    func operationForOperationType() -> ([Double], [[Double]]?) -> Double {
        switch self {
        case OperationType.Addition:
            return { (a, b) in a.reduce(0, combine: {$0 + $1})}
        }
    }
}

var op = OperationType.Addition
let f = op.operationForOperationType()
let arr: [Double] = [1, 5, 2]
f(arr, nil) // actually outputs 8 now