4

Swift has first class functions that can be passed as arguments.

func a() {
}

func b(x: ()) {
}

// Pass a to b…
b(a)

Swift has generic functions.

func generic<T>(x: T) {
}

But, does Swift let me pass a generic function as an argument to another function?

let anIntService = Service<Int>()
let astringService = Service<String>()

func attach<T>(service: Service<T>, to value: T) {
  // Perform type safe attaching of `value` to `service`.
}

func doAttaching(attach: (Service<T>, to T)->Void) {
  attach(anIntService, to: 42)
  attach(aStringService, to: "Hello World!")
}

doAttaching(attach)

…Or does it only let me pass a specific instantiation of a generic function?

If this is possible, please illustrate the syntax for defining a function that accepts a generic function as an argument.

If this isn't supported, a workaround is to define the generic function as a method of a struct, or something, and pass an instead of that. This is not ideal though, as the consuming function doesn't get such a nice calling syntax, they need to do:

func doAttaching(attach: Attacher) {
  attacher.attach(anIntService, to: 42)
  attacher.attach(aStringService, to: "Hello World")
}
Benjohn
  • 13,228
  • 9
  • 65
  • 127

3 Answers3

4

This feature is commonly called Higher-Kinded Types (HKT), and is not currently supported in Swift.

It has, however, been discussed on the swift-evolution mailing list.

jtbandes
  • 115,675
  • 35
  • 233
  • 266
  • Hah! Really? :-) That's funny, because I'd read about higher kinded types in the past a few times, and had absolutely no idea what they were talking about. Now I know! Super – it'd be lovely if it makes a future version. Thank you for the reply. – Benjohn May 14 '16 at 07:22
0

Yes, here is an example:

func identity<T>(param: T) -> T {
    return param
}

func callFunction<U>(function: U->U, paramater: U) -> U {
    return function(paramater)
}

let param = 123

let result = callFunction(identity, paramater: param);

print(result)

(You can run it here)

Alexander
  • 59,041
  • 12
  • 98
  • 151
  • 2
    Thanks for the reply, but I don't think this does what I need. So, the called function in your example, `callFunction`, still isn't getting the generic function. It's getting a specific instance of it, determined by the type of the `parameter` that you call with – in this case `123`, so an Int. I want to pass the `identity` in your example as a _fully generic_ function to `callFunction`. The definition of `callFunction` can then invoke its `function` argument with multiple types. – Benjohn May 13 '16 at 21:24
  • Oh I see, sorry, I misunderstood the post :( – Alexander May 15 '16 at 15:52
  • No problem! Thanks anyway :-) – Benjohn May 15 '16 at 15:56
0

I realised, five years after asking this question, Swift supports something a little like this which can be useful via callAsFunction.

Here's an example:


final class Service<T> {
    // Implementation here
}

final class Attacher {
    // Important state here.
    var state = Void()
    
    func callAsFunction<T>(service: Service<T>, to: T) {
        // Implementation here.
    }
}

func doAttaching(attach: Attacher) {
    attach(service: Service<Int>(), to: 42)
    attach(service: Service<String>(), to: "Hello World!")
}

A Repeater can be passed in to generic code and provide useful behaviour.

Benjohn
  • 13,228
  • 9
  • 65
  • 127
  • I'm going to mark my own question as the right answer, which feels pretty duchey, but it has been 5 years. – Benjohn Jan 13 '22 at 09:19