SE-0376: Function back deployment

Props to you, Allan et al! I had forgotten all about this proposal, but this will definitely improve the situation for Apple frameworks. its_happening.avi

A few comments:

  • I don’t think this is incompatible with @inlinable; if you use both, you’re saying the body must be used on older OSs and may be used on later ones. That’s a pretty subtle place to be, though, so I can understand leaving it out for now, especially since it would require more implementation work. I suspect it will be interesting in the future, though; many things currently marked @_alwaysEmitIntoClient are trivial helpers that are often completely inlined away.

  • The bodies of @inlinable functions must always be valid for all deployment targets, which has gotten the stdlib into trouble before! A (non-@inlinable) @backDeploy function has a similar concern: the parts not guarded by availability must always be valid for all deployment targets. Since that’s statically optimizable, though, that shouldn’t be a problem; I just predict a fair amount of this idiom:

@available(toasterOS 1, *)
@backDeploy(before: toasterOS 2)
func batchToast() {
  if #available(toasterOS 3, *) {
    // Depends on new API.
    // The check would match whatever API is used,
    // not the back-deploy floor.
    self.slots.forEach { $0.startToasting() }
  } else {
    // Only this part will be back-deployed
    self.startToasting()
    // etc
  }
}
7 Likes