user2727195
user2727195

Reputation: 7340

Curried functions in SWIFT

After reading Ole's post http://oleb.net/blog/2014/07/swift-instance-methods-curried-functions/

What I understood is that you can call a method of any class in a different context or scope. If I understood it correctly then it's the same as apply or call in javascript.

Here's my attempt using this for the Observer pattern.

I've a problem in self.method(self.context)(message), the error says (Messaging) -> $T6 is not identical to 'Void'

protocol Messaging {
    var message: String { get set }
}

class Observer {
    var method: Messaging -> Void
    var context: AnyObject

    init(method: Messaging -> Void, context: AnyObject) {
        self.method = method
        self.context = context
    }

    func notify(message: Messaging) {
        self.method(message)
        //self.method(self.context)(message) // Houston, we have a problem
    }
}

public class Message: Messaging {
    var message: String

    public init(message: String) {
        self.message = message
    }
}

class TestObserver {

    func createAndNotifiy() {
        var observer = Observer(method: self.handleMessage, context: self)
        observer.notify(Message(message: "TestMessage"))
    }

    func handleMessage(message: Messaging) -> Void {
        println(message.message)
    }
}

var test = TestObserver()
test.createAndNotifiy()

inside notify method I've attempted to call the passed method in the passed context (I've used context as self but it could be a different context too)

My objective is to make it work for any context passed in.

Edit: Is it that who's function I ever pass in, it automatically gets associated to that context, for instance Observer(method: self.handleMessage... in this case handleMessage is implicitly/explicitly bound to self in this case and I shouldn't really care about passing self as an additional param (as context), cause self.method(message) calls the method in context of the bound object automatically? that's my assumption, looking forward to a solid opinion.

but irrespective still also would like to know how to get the curried approach work in this case

Upvotes: 0

Views: 493

Answers (1)

Airspeed Velocity
Airspeed Velocity

Reputation: 40973

There’s a difference between self.methodname (which you are using), and Classname.methodname.

The former, when called within a class’s method, will give you a function bound with that class instance. So if you call it, it will be called on that instance.

The latter gives you a curried function that takes as an argument any instance of Classname, and returns a new function that is bound to that instance. At this point, that function is like the first case (only you can bind it to any instance you like).

Here’s an example to try and show that a bit better:

class C {
    private let _msg: String
    init(msg: String) { _msg = msg }

    func print() { println(_msg) }

    func getPrinter() -> ()->() { return self.print }
}

let c = C(msg: "woo-hoo")
let f = c.getPrinter()
// f is of type ()->()
f() // prints "woo-hoo"

let d = C(msg: "way-hey")

let g = C.print
// g is of type (C)->()-(),
// you need to feed it a C:
g(c)() // prints "woo-hoo"
g(d)() // prints "way-hey"

// instead of calling immediately,
// you could store the return of g:
let h = g(c)
// at this point, f and h amount to the same thing:
// h is of type ()->()
h() // prints "woo-hoo"

Finally, looks like you’re trying, with AnyObject, to take any kind of class and pass that into your curried instance method. That won’t fly – that curried method will specifically need a type of the class it was taken from. No good trying to feed it something else.

Upvotes: 1

Related Questions