Mutable values in partially-applied methods

A couple times recently I've run into situations where this doesn't compile:

foo.frobnicate(bar.mutatingFunc)

but then this does:

foo.frobnicate { bar.mutatingFunc() }

If the second is allowed, why not the first?

1 Like

I can reproduce the issue in Xcode 15.0.

struct Foo {
    // It takes a non-escaping closure
    func run(_ c: () -> Void) {
        c()
    }
}

struct Bar {
    var x: Int = 1

    mutating func mutate() {
        x = 2
    }
}

func test() {
    let foo = Foo()
    var bar = Bar()

    // test 1: this works
    foo.run {
        bar.mutate()
    }

    // test 2: this doesn't work
    // Error: Escaping autoclosure captures 'inout' parameter 'self'
    foo.run(bar.mutate)
}

There are two things odd:

  1. The "self" in the error message. I suspect it should be "bar" instead?

  2. Foo.run() takes a non-escaping closure, but the compiler generates an escaping autoclosure (and hence the error).

Maybe it's a bug?


Off-topic...a comment on the terminology. I think bar.mutate is a function, not a partially applied function. I don't think Swift has language level support for partially applied function.

2 Likes

Allowing this in non-escaping position seems reasonable to me (unless I’m missing something), and regardless that error message should be better.

Interestingly up until Swift 5.5 godbolt gave me this wording:

error: partial application of 'mutating' method is not allowed

you are right, "partial application" / currying is the term of art for something else we don't have in swift.

1 Like

It is partial application if you think of self as an argument. It’s not general partial application, though.

3 Likes

Where's self in the above example?

bar, that would be self inside the body of mutate if this were allowed.

1 Like