# @backDeployed is operating as an override instead of only for use in unsupported platforms versions

**URL:** <https://forums.swift.org/t/backdeployed-is-operating-as-an-override-instead-of-only-for-use-in-unsupported-platforms-versions/68071>\
**Category:** Using Swift\
**Tags:** bug, availability\
**Created:** [October 25, 2023, 11:03pm UTC](https://forums.swift.org/t/backdeployed-is-operating-as-an-override-instead-of-only-for-use-in-unsupported-platforms-versions/68071 "2023-10-25T23:03:25Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![NSProgrammer](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nsprogrammer/32/7254_2.png) [@NSProgrammer](https://forums.swift.org/u/NSProgrammer)\
**Post date:** [October 25, 2023, 11:03pm UTC](https://forums.swift.org/t/backdeployed-is-operating-as-an-override-instead-of-only-for-use-in-unsupported-platforms-versions/68071/1 "2023-10-25T23:03:25Z")

</div>

We have been facing a lot of headaches recently from unexpected behavior of APIs that we have [`@backDeployed`](https://github.com/apple/swift-evolution/blob/main/proposals/0376-function-back-deployment.md) since Xcode 15 and iOS 17 released. Long story short, I've uncovered that any API that we `@backDeployed` is being called not only on OSes "before" the platform deployed version, but on OSes "after" the platform deployed version too.

This is trivially reproducible with unit tests or a playground:

```swift
import UIKit

public extension Locale.LanguageCode {
  @backDeployed(before: macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0)
  var debugDescription: String { // <-- introduced in iOS 17
    get {
      if #available(iOS 17, macOS 14.0, *) {
        return "17"
      }
      return self.identifier
    }
  }
}

func test() {
  let locale = Locale(identifier: "en_US")
  let languageCode = locale.language.languageCode!
  
  
  let desc = languageCode.debugDescription
  // ^ This print should yield "en" on iOS 16 & 17
  // but it yields "17" on iOS 17 (proving the @backDeployed API is actually being treated as an override instead thunking to the platform deployed version).
  // You can comment out the @backDeployed `debugDescription` above to see it go back to correct behavior
}

test()

```

Effectively, we overriding any API we like using `@backDeployed` instead of just back deploying.

Is this something that can be addressed in a bug fix revision to Swift (and ideally deployed to Xcode 15.1 before it exits beta)?

---

<div class="post-metadata">

**Author:** ![NSProgrammer](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nsprogrammer/32/7254_2.png) [@NSProgrammer](https://forums.swift.org/u/NSProgrammer)\
**Post date:** [October 25, 2023, 11:34pm UTC](https://forums.swift.org/t/backdeployed-is-operating-as-an-override-instead-of-only-for-use-in-unsupported-platforms-versions/68071/2 "2023-10-25T23:34:14Z")

</div>

I repro the same issue on Xcode 15.1 beta 1

---

<div class="post-metadata">

**Author:** ![tshortli](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tshortli/32/15850_2.png) [@tshortli](https://forums.swift.org/u/tshortli)\
**Post date:** [October 26, 2023, 1:31am UTC](https://forums.swift.org/t/backdeployed-is-operating-as-an-override-instead-of-only-for-use-in-unsupported-platforms-versions/68071/3 "2023-10-26T01:31:54Z")

</div>

I think you have misinterpreted what the `@backDeployed` attribute does and what it is meant to be used for. `@backDeployed` was designed for use in the implementation of frameworks that _ship with an OS_. The attribute is not designed give you a way to provide your own polyfills for arbitrary functions in the SDK, so I don't think it will have the effect you're looking for if I'm interpreted what you're trying to accomplish correctly.

In your example, you have declared your own computed property `debugDescription` for `Locale.LanguageCode`. Your declaration does not "override" the one in Foundation; it just exists simultaneously in your module as a different function that could be called. Whether or not your implementation is called at any given call site depends on which declaration the compiler statically resolves `debugDescription` to. If the compiler resolves the call to your declaration, instead of the one from the SDK, then the `@backDeployed` attribute on your implementation will cause the compiler to emit a call to an intermediary thunk that calls either your original function or a copy of your function, which won't accomplish anything useful since its a function in the same module and both the original and the fallback copy will always have an identical implementation.

---

<div class="post-metadata">

**Author:** ![NSProgrammer](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nsprogrammer/32/7254_2.png) [@NSProgrammer](https://forums.swift.org/u/NSProgrammer)\
**Post date:** [October 26, 2023, 1:53am UTC](https://forums.swift.org/t/backdeployed-is-operating-as-an-override-instead-of-only-for-use-in-unsupported-platforms-versions/68071/4 "2023-10-26T01:53:03Z")

</div>

Where can I find documentation on this? I have read and re-read to enhancement request and, though it lists framework owners as a use case, it never restricts it to that usage. It also uses javascript polyfills as an example comparison, and lastly the code example of how the compiler would produce a thunk is perfectly compatible in concept with extensions outside the deploying framework adding @backDeployed. In fact, if you google it, there are many examples of doing the exact same thing we are doing as consumers of a library we want extended deployment support for the same API.

Is it possible to implement a duplicate API for an existing API that is imported already? Im pretty sure the compiler will error on that. This is circumventing that.

I can appreciate that there may be some presumed nuance that is not explicitly documented. So Im wondering if the feature should be codified to support this real world use case, or if there ought to be documentation added to make it explicitly clear what is and what is not expected. Ideally with compiler warnings when using it in a way that is not supported.

I’m open to anything, but I have not encountered anyone who interpreted this feature to be restricted the way you’ve described, so we have broken expectations (intentional or not).

Thank you for engaging in this topic, I appreciate your response!

---

<div class="post-metadata">

**Author:** ![tshortli](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tshortli/32/15850_2.png) [@tshortli](https://forums.swift.org/u/tshortli)\
**Post date:** [October 26, 2023, 6:28am UTC](https://forums.swift.org/t/backdeployed-is-operating-as-an-override-instead-of-only-for-use-in-unsupported-platforms-versions/68071/5 "2023-10-26T06:28:04Z")

</div>

> [@NSProgrammer](#):
>
> Where can I find documentation on this? I have read and re-read to enhancement request and, though it lists framework owners as a use case, it never restricts it to that usage.

The proposal document is at the moment the most detailed documentation for this feature that exists. The attribute probably ought to be covered in The Swift Programming Language, where the intended use case could be clarified officially.

> [@NSProgrammer](#):
>
> It also uses javascript polyfills as an example comparison

In hindsight, the proposal ought to have been a lot clearer about this analogy because this confusion is probably inevitable. `@backDeployed` allows ABI stable libraries to extend the effective availability of their _own_ public APIs to older OSes, where the API isn't actually present in the library. This resembles a polyfill mechanically, but it doesn't support the same patterns as folks may be used to from other languages. It does not help a module to overlay a polyfill on top of an API from another module.

> [@NSProgrammer](#):
>
> Is it possible to implement a duplicate API for an existing API that is imported already? Im pretty sure the compiler will error on that. This is circumventing that.

The attribute does not affect how this aspect of the language works. In many contexts, Swift allows you to introduce declarations that shadow other declarations. For example, function parameters can be shadowed by local variables:

```swift
func foo(x: Int) {
  let x = 2
  print(x)
}
foo(x: 1) // "2"

```

Swift also allows members of extensions to shadow members of a type declared in another module. For example, in the program below I've declared my own `count` property on the `Swift.String` type that always returns 1 instead of the real length:

```swift
extension String {
  var count: Int { return 1 }
}

print("string".count) // 1
print(("string" as any Collection).count) // 6

```

I suppose you could use this technique to transparently redirect calls to APIs from the SDK in your module if you really wanted to implement a shim without changing any of the existing call sites, but it's important to understand exactly what's happening and what the limitations of the approach are. As demonstrated by the output from the second `print()`, the `count` declaration I wrote hasn't somehow dynamically replaced `String.count` in the entire program; it's just an alternative function that the compiler may statically resolve specific calls to. The witness of the `count` requirement of `Collection` still calls the `count` implementation in the standard library, since that's the one the compiler resolved the witness to when compiling `String`'s conformance to `Collection` in the standard library, and so the second `.count` invokes the standard library's implementation.

If you follow how shadowing operates in the example above, then you can take it a step further to understand what adding the `@backDeployed` attribute to the `count` declaration in the example does: it introduces a thunk every time _that specific instance_ of `count` would be called. For callers in the same module this accomplishes basically nothing at all (and the call to the thunk would actually be optimized away). For callers in another module, it would do something, but still not something very useful since the original implementation of the function doesn't ship with the OS and therefore the thunk is still just dispatching between two copies of a function that doesn't live in the OS.

> [@NSProgrammer](#):
>
> I can appreciate that there may be some presumed nuance that is not explicitly documented. So Im wondering if the feature should be codified to support this real world use case, or if there ought to be documentation added to make it explicitly clear what is and what is not expected.

It would be interesting to discuss how a feature that allows modules to provide polyfills for declarations in other modules would work. But that would be a separate language feature to pitch and discuss, and it isn't the problem we set out to solve by introducing `@backDeployed` into the language. I encourage anyone who wants to see such a feature to start a discussion thread in the Evolution section of the forum.

> [@NSProgrammer](#):
>
> Ideally with compiler warnings when using it in a way that is not supported.

If there are specific examples of code that ought to be considered invalid that the compiler can diagnose to help alleviate some of the confusion, I'm happy to implement them. Unfortunately, though, the original code example in this thread is a perfectly valid application of the attribute; you could copy-paste that code into the implementation of some framework in Apple's SDK and it would be a 100% valid API, if a bit weird. I think the crux of the problem is that Swift happens to allow you to use extensions to shadow the members of types, and therefore if you have this misunderstanding about the purpose of `@backDeployed` then nothing will stop you from writing this code and thinking it does something that it doesn't. I think the obvious next step is to ensure there's really clear official documentation for the feature, though, and I'll try to get the ball rolling on that.

---

<div class="post-metadata">

**Author:** ![NSProgrammer](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nsprogrammer/32/7254_2.png) [@NSProgrammer](https://forums.swift.org/u/NSProgrammer)\
**Post date:** [October 26, 2023, 1:29pm UTC](https://forums.swift.org/t/backdeployed-is-operating-as-an-override-instead-of-only-for-use-in-unsupported-platforms-versions/68071/6 "2023-10-26T13:29:23Z")

</div>

> [@tshortli](#):
>
> it's important to understand exactly what's happening and what the limitations of the approach [(i.e. @backDeployed)] are

Yes, I do understand that this is going to be based on module import shadowing the original implementation. Thank you for describing it in detail with a code example for the posterity of this post!

> [@tshortli](#):
>
> and so the second `.count` invokes the standard library's implementation

Sadly, with `@backDeployed`, there isn't a mechanism to call the shadowed API. I think that would help this feature notably if the implementer could redirect to the shadowed API when it notes the OS version being high enough. In particular, there is a pain point when `@backDeployed` is used with an initializer, because the semantic requirements of initializers, there's no way to "dig yourself out" (e.g. just have a different object created and returned without calling any `self.init` designated initializer).

> [@tshortli](#):
>
> It would be interesting to discuss how a feature that allows modules to provide polyfills for declarations in other modules would work. But that would be a separate language feature to pitch and discuss, and it isn't the problem we set out to solve by introducing `@backDeployed` into the language. I encourage anyone who wants to see such a feature to start a discussion thread in the Evolution section of the forum.

Yes, agreed. Now that I understand that the feature is not as one would interpret it from the `@backDeployed` proposal document, I'm mostly in a learning phase of the edges of this feature -- fully requesting a new feature would be something to pursue in the future.

> [@tshortli](#):
>
> I think the obvious next step is to ensure there's really clear official documentation for the feature, though, and I'll try to get the ball rolling on that.

I couldn't agree more! Thank you!

**Concluding**

Thank you for the discussion and education here. I will work on undoing our `@backDeployed` from our codebase, which is already seeing many hundreds of usages in the code base... the tricky thing about a great _perceived_ solution, it gets a adopted rapidly and broadly.

1. **Better documentation**. It is clear from Googling usages of `@backDeployed` and from conversations with very seasoned Swift devs, including language contributors, that this feature is expected to be a polyfill.
2. **Better warnings from the compiler**. As valid as what we're doing is in to the compiler _if_ we were implementing it in the deploying framework, it seems pretty clear that if you are implementing a `@backDeployed` API when you should not be (i.e. me), the compiler should warn you that you are not using `@backDeployed` with its express intent and therefor beware of dragons.

Thanks again 🙂

---

<div class="post-metadata">

**Author:** ![tshortli](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tshortli/32/15850_2.png) [@tshortli](https://forums.swift.org/u/tshortli)\
**Post date:** [October 26, 2023, 4:07pm UTC](https://forums.swift.org/t/backdeployed-is-operating-as-an-override-instead-of-only-for-use-in-unsupported-platforms-versions/68071/7 "2023-10-26T16:07:25Z")

</div>

I filed an [issue](https://github.com/apple/swift-book/issues/202) on TSPL to track documentation for `@backDeployed`.

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [October 26, 2023, 4:25pm UTC](https://forums.swift.org/t/backdeployed-is-operating-as-an-override-instead-of-only-for-use-in-unsupported-platforms-versions/68071/8 "2023-10-26T16:25:34Z")

</div>

> [@tshortli](#):
>
> I think you have misinterpreted what the `@backDeployed` attribute does and what it is meant to be used for. `@backDeployed` was designed for use in the implementation of frameworks that _ship with an OS_. The attribute is not designed give you a way to provide your own polyfills for arbitrary functions in the SDK

FWIW, this is exactly the reason I argued against making `@backDeployed` a public-facing feature. It's a good feature, but only Apple's SDK engineers have meaningful reason to use it.

> [@\[Returned for revision\] SE-0376: Function back deployment](https://forums.swift.org/t/returned-for-revision-se-0376-function-back-deployment/61507/2):
>
> The issue is not that it is "primarily an Apple platform concern" - it is that it is exclusively meaningful for engineers _creating_ Apple's SDK libraries. In that respect, it could not be more different to the availability system.
> 
> Joe Programmer, writing code which will run on an Apple platform, needs to know about availability. They may need to conditionalise calling certain APIs using `if #available`, or annotate _their own_ APIs with `@available` if they absolutely depend on an availability-limited platform API.
> 
> Joe will never have to write `@backDeploy`. He has no meaningful way to use that feature, because there is no chance whatsoever that code compiled against a newer interface will load an older version of his library at runtime. That is a problem that only Apple's SDK engineers need to worry about.

We should definitely clarify its intended use in documentation. In fact, I would go even further and disallow it from regular swift code (so misunderstandings like the one in this thread result in a compiler error), unless one passes in a special compiler flag to enable it.

If users are attaching `@backDeploy` to their code, they're just making a mistake. Why would we let them do that?

---

<div class="post-metadata">

**Author:** ![NSProgrammer](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nsprogrammer/32/7254_2.png) [@NSProgrammer](https://forums.swift.org/u/NSProgrammer)\
**Post date:** [October 26, 2023, 5:18pm UTC](https://forums.swift.org/t/backdeployed-is-operating-as-an-override-instead-of-only-for-use-in-unsupported-platforms-versions/68071/9 "2023-10-26T17:18:20Z")

</div>

I completely agree, Karl. We are in a serious technical debt bind now because of how this feature was exposed to our devs in our iOS code base (thousands of devs) and things went forward without even a warning. I am super aligned on it's usage, but it is an expensive foot-gun we have to undo -- at least it has only been since June vs any longer.

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [October 26, 2023, 5:41pm UTC](https://forums.swift.org/t/backdeployed-is-operating-as-an-override-instead-of-only-for-use-in-unsupported-platforms-versions/68071/10 "2023-10-26T17:41:43Z")

</div>

> [@Karl](#):
>
> FWIW, this is exactly the reason I argued against making `@backDeployed` a public-facing feature. It's a good feature, but only Apple's SDK engineers have meaningful reason to use it.

In reviewing the proposal, we considered this option as an alternative. However, it would have been strictly worse: the standard library and other first-party libraries will make extensive use of the feature, so users will _see_ it whether or not it is documented; there are a number of underscored attributes meant for internal use only which users have widely adopted in this way.

A key purpose of making `@backDeployed` a reviewed and publicly documented feature was precisely so that the semantics are set down clearly (and so that backdeployment information about new APIs is surfaced in user-facing documentation alongside availability information). Both during review, and afterwards in the explanatory articles I've seen around the internet (for example: [1](https://www.avanderlee.com/swift/backdeployed-function-back-deployment/), [2](https://www.hackingwithswift.com/swift/5.8/function-back-deployment)), I've seen pretty accurate descriptions of who or what it's for.

However, if the proposal text is falling short in that regard, we may need to work on editorial revisions, and certainly it is expected that _TSPL_ will have accurate information on the attribute.

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [October 26, 2023, 6:05pm UTC](https://forums.swift.org/t/backdeployed-is-operating-as-an-override-instead-of-only-for-use-in-unsupported-platforms-versions/68071/11 "2023-10-26T18:05:45Z")

</div>

I'm not sure those example articles you linked to are really _crystal clear_ about the intended usage.

The first article, for instance, begins as following:

> The @backDeployed attribute in Swift allows you to extend function availability back to older OS versions. It’s beneficial for framework developers to make new declarations available to apps with a lower minimum deployment target compared to the framework.

I can certainly imagine developers reading that and coming away with the wrong impression. It continues:

> The @backDeployed attribute allows you to back-deploy functions and make them available to apps running on older OS versions.

"allows **you** to back-deploy" -- No. That's wrong. It's not for _you_.

Then at the very end, there's a section:

> Who should use Function Back Deployment?
> 
> Function back deployment is primarily helpful for SDK developers. During normal app development, we bundle our latest library version directly with our app removing the need for @backDeployed attribute usage. In other words, all new code we write will be available immediately and doesn’t require back deployment.

That's also not absolutely 100% clear. Lots of developers write libraries which they call "SDKs". There's a Facebook SDK, Google Maps SDK, Twitter SDK, etc.

There _are_ those two sentences about bundling the latest library version, but I also wouldn't really say they are clear enough in spelling out that this feature is _literally_ only for people who work at Apple. Especially in the context of the rest of the article, which frequently seems to suggest that this feature is something I (some Swift developer) might be interested in using.

The second article doesn't mention explicitly who the feature is for, either.

So I don't come away from those articles with the same positive impression as you do; I look at them and come away concerned. This is a _very_ specialised feature, and these articles are explaining it from the perspective of somebody who might want to _use_ it, rather than from the perspective of somebody who wonders what it means when they _read it_ in an interface.

* * *

Anyway, even if it is going to be publicly documented, I don't think it should be publicly available for use. You should have to opt-in to it.

---

<div class="post-metadata">

**Author:** ![scanon](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/scanon/32/2445_2.png) [@scanon](https://forums.swift.org/u/scanon)\
**Post date:** [October 26, 2023, 6:08pm UTC](https://forums.swift.org/t/backdeployed-is-operating-as-an-override-instead-of-only-for-use-in-unsupported-platforms-versions/68071/12 "2023-10-26T18:08:46Z")

</div>

> [@Karl](#):
>
> Anyway, even if it is going to be publicly documented, I don't think it should be publicly available for use. You should have to opt-in to it.

How far would we get just from having it warn if it's used outside of library evolution?

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [October 26, 2023, 6:16pm UTC](https://forums.swift.org/t/backdeployed-is-operating-as-an-override-instead-of-only-for-use-in-unsupported-platforms-versions/68071/13 "2023-10-26T18:16:10Z")

</div>

Don't XCFrameworks build with library evolution enabled? (Genuine question - I'm not sure).

If they do, then it's not precisely the same thing. Authors of XCFrameworks should also get diagnostics if they attempt to use `@backDeploy`. Still, it would be better than nothing, as it would give diagnostics for at least some Swift code.

---

<div class="post-metadata">

**Author:** ![tshortli](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tshortli/32/15850_2.png) [@tshortli](https://forums.swift.org/u/tshortli)\
**Post date:** [October 26, 2023, 7:36pm UTC](https://forums.swift.org/t/backdeployed-is-operating-as-an-override-instead-of-only-for-use-in-unsupported-platforms-versions/68071/14 "2023-10-26T19:36:31Z")

</div>

> [@scanon](#):
>
> How far would we get just from having it warn if it's used outside of library evolution?

That’s certainly an option. But one problem with a requirement like that (and an accompanying diagnostic) is that some users will see the diagnostic and just think that the problem is that they haven’t enabled library evolution, rather than the problem being that they’re attempting to use a feature that isn’t appropriate for their use case. Now they have two problems.
