Partial application of mutating methods

Over the years there have been a couple of questions about partial application of mutating methods in contexts where it's impossible to go wrong (see here and here). I have yet to find a way to accomplish this.

Here's my own context:

struct Thing {
  var name: String

  mutating func capitalize(all: Bool) {
    if all {
      name = name.uppercased()
    } else {
      name = name.capitalized
    }
  }
}

func curryMutator<A, B>(
  _ f: (inout A) -> (B) -> Void,
  with b: B
) -> (inout A) -> Void {
  { inoutA in
    f(&inoutA)(b)
  }
}

let capitalizeThing = curryMutator(Thing.capitalize, with: true) // error: Partial application of 'mutating' method is not allowed

I'm guessing that the compiler cannot determine that I'm not actually going to be mutating anything outside of its allowed scope. But is there any way around this?

There is no solution, but it could be different:

SE-0042 was supposed to solve this problem, among others. It was initially accepted, but never implemented, so it had to be revoked. People suggested to resurrect it in a new way, but it didn't go anywhere either.

In the end, only the considered alternative was implemented so that you get this error instead of miscomplied code (see the last paragraph of the Motivation section of that proposal).

2 Likes

Cool, thank you for these references! Very helpful.

I could also see something similar to Pointfree’s CasePaths being implemented here, at least in terms of syntax, (although that would apply more to static rather than instance methods, so perhaps not). In any case, it’s a bit of a bummer, IMO; hopefully someday folks with compiler know-how can come back around to it. Or I can gain some compiler know-how... :grin: