Create self-mutating closure without IUO?

Example: let's create this…

[ "πŸ•›", "πŸ•§", "πŸ•", "πŸ•œ", "πŸ•‘", "πŸ•",
  "πŸ•’", "πŸ•ž", "πŸ•“", "πŸ•Ÿ", "πŸ•”", "πŸ• ",
  "πŸ••", "πŸ•‘", "πŸ•–", "πŸ•’", "πŸ•—", "πŸ•£",
  "πŸ•˜", "πŸ•€", "πŸ•™", "πŸ•₯", "πŸ•š", "πŸ•¦",
  "πŸ•›"
]

…with this:

Array( πŸ•°.prefix(25) )

We'll do that with a simple example of a use case for the thread title question.

It is possible to reduce branch count by changing what happens in the next of a sequence, like so:

var πŸ•°: AnySequence<String> {
  func addHalfHour(toHour hour: UInt32) -> UInt32 {
    hour + 12
  }

  func getNextHalfHour(afterHour hour: UInt32) -> UInt32 {
    getNext = getNextHour
    return addHalfHour(toHour: hour)
  }

  let twelve: UInt32 = 128347
  var getNext: ( (UInt32) -> UInt32 )! = getNextHalfHour

  func getNextHour(after30 halfHour: UInt32) -> UInt32 {
    getNext = getNextHalfHour
    return
      ( halfHour == addHalfHour(toHour: twelve)
        ? twelve
        : halfHour
      )
      - 11
  }

  return .init(
    sequence(first: twelve) { getNext($0) }
    .lazy
    .map { String(Unicode.Scalar($0)!) }
  )
}

Given that getNext will always mutate itself, is there a solution (without introducing a branch) to avoid having to make it optional?

Before others offer a solution to the problem you've posed, I would note that a branch is going to be significantly more maintainable and faster at runtime than trying to mutate through a closure capture, regardless of if you can do this by avoiding a layer of optionality or not...

Not if the switch statement is large and the cases are expensive.

What kind of numbers do you have to back up that assertion?

:stopwatch::point_left:

I was asking if you had done any performance profiling and had come up with perhaps a perf run or instruments trace that would elucidate the problem. Humans have a terrible intuition for where performance problems actually lie in a lot of cases, and it would really help us to see a concrete example so we can make sure this isn't e.g. a bug in the optimizers or a misconfiguration issue.

And if you have established that the self-modifying closure is in fact faster, an IUO or Optional would still be your best bet for avoiding the circularity problem. If the branch from the unwrap is itself an unacceptable cost, you could use unsafelyUnwrapped to unwrap the value without checking for nil.

1 Like