So this question has an obvious answer: "because the compiler won't let you" but I'm hoping someone can explain to me why this part of Swift works the way it does.
I ran into this question because I was building a view controller that needed to satisfy a protocol (UIImagePickerControllerDelegate). The protocol requires a callback function to call after a user selected an image. I wanted to be able to change the callback behavior at runtime.
Coming from a Python background, I figured that should be easy: just define the callback method on my class to satisfy the protocol and then redefine it later by just reassigning to it. That works perfectly fine in Python:
class Foo(object):
def bar(self):
print "bar"
foo = Foo()
foo.bar() # output "bar"
def baz():
print "baz"
foo.bar = baz
foo.bar() # output "baz"
But it doesn't work in Swift (even though I can do very nearly the same thing by declaring a variable to hold a closure):
import UIKit
class Foo {
func bar() -> String {
return "bar"
}
var baz: ()-> String = {
return "baz"
}
}
let foo = Foo()
foo.bar() // output: bar
foo.baz() // output: baz
let gee = {
return "gee"
}
foo.baz = gee
foo.baz() // output: gee
foo.bar = gee // error: cannot assign to bar in foo
So the question...why does Swift work this way? It's clearly not because it's impossible to alter function routing at runtime (otherwise the closure assignment wouldn't work). My best guess is that it's analogous to the let/var distinction for variables and that using "func" is implicitly telling the compiler that a function should be immutable. And I grant that it may be better to make instance methods immutable by default. But it is annoying when we need to comply with rigid protocols from UIKit. At least it would be nice if I could use a variable to satisfy a function requirement in a protocol.
(For the curious: I worked around this issue by declaring an instance variable to hold a closure that can be reassigned. I then declared the required protocol function and made it do nothing but call the closure. Which might(?) cause a retain cycle, but works.)