0

Not sure if this is the best approach but I want to have functions accessible by an index and would prefer not to use a dictionary. So I was thinking of putting them into an array.

var array = [ func1, func2, ... ]

It looks like this is possible since functions are first class citizens.

BUt I'm wondering if you can do this on classes. That is, pass a function from a class instance to an array, without losing performance with extra closures.

class Foo {
  var array: [Function]

  init() {
    array = [ f1, f2 ]
  }

  func f1() {
    return array.length
  }

  func f2(a: Int, b: Int) {
    // ... the functions are all different.
  }
}

Wondering if anything like that is possible.

10
  • Possibly helpful: stackoverflow.com/q/55038194/1187415. Commented Mar 15, 2019 at 19:36
  • Do all the functions have the same signature? Your first func f1() seems to return a value. Commented Mar 15, 2019 at 19:44
  • No sorry, they will all be different, I will update. Commented Mar 15, 2019 at 19:46
  • 1
    Then f1 and f2 have different types. You cannot store them in a common array (only as Any which makes things ugly). Commented Mar 15, 2019 at 19:49
  • 1
    What are you trying to achieve? With var array: [Any] you would have to cast each element back to the correct function type in order to call the function, i.e. you have to know the signature of every element (or try all possible signatures). Commented Mar 15, 2019 at 20:20

1 Answer 1

2

Swift Arrays are homogeneous, but you can use Any to box any type at the expense of losing the type information, so yes you can stick all of your functions into a single array even though they have different types. I don't particularly think its a good idea, but it does in fact work:

import UIKit
import PlaygroundSupport


class Foo {
    var array: [Any] = []

    init() {
        array = [ f1, f2 ]
    }

    func f1() -> Int {
        return array.count
    }

    func f2(a: Int, b: Int) {
        // ... the functions are all different.
    }
}

maybe this is slightly less horrible if you use the Objective C run time, since its dynamic and you can use actually use perform selector with arguments to invoke the selectors, but I still don't recommend it:

import UIKit
import PlaygroundSupport


class Foo {
    var array: [Selector] = []

    init() {
        array = [#selector(f1), #selector(f2) ]
    }

    @objc func f1() -> Int {
        return array.count
    }

    @objc func f2(a: Int, b: Int) {
        // ... the functions are all different.
    }
}

EDIT:

Option 3, enum with associated values (come up with more meaningful names than I have here):

import UIKit
import PlaygroundSupport


class Foo {

    enum Function {
        case void_Int(() -> Int)
        case intInt_Void((Int,Int) -> Void)
    }

    var array: [Function] = []

    init() {
        array = [.void_Int(f1), .intInt_Void(f2) ]
    }

    @objc func f1() -> Int {
        return array.count
    }

    @objc func f2(a: Int, b: Int) {
        // ... the functions are all different.
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

This definitely answers the question, but yeah I can see it not being ideal. I want to dynamically invoke a function given an integer, so an array was the first choice. Wondering what you would recommend instead. A switch statement would work, but that adds a lot of processing given 100's of functions. A dictionary might work but that uses the hash under the hood. Maybe there are other approaches you know about.
If you truly don't need any type, but only finitely many types, use an enum with associated values for each possible type. This lets you put all of the functions into one array WITHOUT losing the string typing (ie the functions are boxed by the enum instead of by Any).
Maybe you wouldn't mind demoing that, I'm going to try learning about enums. It sounds like you're saying an enum with the keys/value pairs being functions, and they will be indexed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.