Reputation: 104065
Given this code:
struct Foo {
func f() {}
}
let f = Foo.f // (Foo) -> () -> ()
Why does f
have the type (Foo) -> () -> ()
and not (Foo) -> ()
? Wouldn’t it make sense for instance methods like Foo.f
to be directly interchangeable with free functions of type (Foo) -> …
?
Upvotes: 1
Views: 104
Reputation: 80801
Why does
f
have the type(Foo) -> () -> ()
and not(Foo) -> ()
?
That's just currently how unapplied instance method references are implemented; they're curried functions that follow the model of "give me an instance, and I'll give you back a partially-applied instance method" (partially applied with that instance).
However this is problematic in some areas, firstly because it's generally more useful for them to be of the form (Self, Args...) -> Ret
, but also more importantly because it because it leads to issues around mutating
methods. These end up looking like (inout Self) -> (Args...) -> Ret
with the current system, which is problematic because the window of mutation for inout
only lasts for the duration of the call.
This means the following currently compiles, but is actually undefined behaviour:
struct S {
var i: Int
mutating func increment() {
i += 1
}
}
var s = S(i: 0)
let unappliedIncrement = S.increment
let increment = unappliedIncrement(&s)
increment() // undefined behaviour
These are the main motivations behind SE-0042, which will change unapplied instance method references from being of the form (Self) -> (Args...) -> Ret
to being of the form
(Self, Args...) -> Ret
(and with inout
, Self
will be inout Self
– allowing the mutation of the instance without UB).
This proposal is yet to be implemented, but once it is, assuming empty parameter lists get flattened out (so you don't end up with a trailing Void
parameter), Foo.f
will indeed be of type
(Foo) -> Void
.
Upvotes: 2
Reputation: 535178
It's because, by saying this:
let f = Foo.f
you've described f
as a class method, Foo.f
. But in your declaration of Foo, f
is an instance method. You have thus accidentally discovered the deep dark secret that instance methods are class methods in disguise; you are seeing the signature of the secret class method.
If you had said
let f = Foo().f
you would have gotten the expected result.
Upvotes: 0