I was looking into how keypaths are compiled as functions, when I noticed something that caught me off-guard. In the following code:
public protocol P {}
public func firstVersion(_ args: [[P]]) -> [P] {
let closure: ([P]) -> [P] = { $0 }
return args.flatMap(closure)
}
public func secondVersion(_ args: [[P]]) -> [P] {
let closure: ([P]) -> [P] = \.self
return args.flatMap(closure)
}
there is a substantial difference in firstVersion
and secondVersion
at some optimization levels. With -Osize
and -Ounchecked
, the compiler outputs a reasonably short implementation for firstVersion
, and then secondVersion
just calls firstVersion
. However, with plain -O
, they get drastically different implementations, with firstVersion
being over twice as long as secondVersion
.
Why are they different? Is \.self
meant to perform differently than { $0 }
?