# \[Pitch\] Attribute to silence Deprecation Warnings for a specified scope

**URL:** <https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791>\
**Category:** Pitches\
**Created:** [June 2, 2022, 8:17pm UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791 "2022-06-02T20:17:03Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![Tino](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tino/32/1073_2.png) [@Tino](https://forums.swift.org/u/Tino)\
**Post date:** [June 5, 2022, 4:42pm UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/21 "2022-06-05T16:42:59Z")

</div>

Deprecation warnings can be really annoying, and this would be better than what we have now — but I don't think this is the best long term solution. Even if you could limit the attribute to certain libraries, that wouldn't be the type of granularity I want.  
When I compile a piece of code for the first time, I want to see all deprecation warnings, and I wouldn't want to hide them from team members by annotating problematic code.  
After all, it's not just a problem of that code, but also of some dependency; so you can't silence it safely.

Therefor, I would definitely prefer a compiler flag — or even take away deprecation handling from the compiler, and make it a responsibility of the linter.

---

<div class="post-metadata">

**Author:** ![NSXPCConnection](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nsxpcconnection/32/31019_2.png) [@NSXPCConnection](https://forums.swift.org/u/NSXPCConnection)\
**Post date:** [June 5, 2022, 4:45pm UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/22 "2022-06-05T16:45:31Z")

</div>

A compiler flag is a good idea too, after all, we could provide both, why not a scope based solution and a project solution? I’ll look into this after I finish implementing `import` support for the current implementation I have. Thank you!

---

<div class="post-metadata">

**Author:** ![NSXPCConnection](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nsxpcconnection/32/31019_2.png) [@NSXPCConnection](https://forums.swift.org/u/NSXPCConnection)\
**Post date:** [June 5, 2022, 4:45pm UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/23 "2022-06-05T16:45:55Z")

</div>

Actually a great idea, I’ll think more about it

---

<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:** [June 5, 2022, 4:53pm UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/24 "2022-06-05T16:53:16Z")

</div>

> [@NSXPCConnection](#):
>
> Is this not overcomplicating it? The solution and implementation I wrote are the best in my eyes, just attach `@ignoreDeprecationWarnings` to whatever scope you’re about to use those symbols in (subclass, function, etc)

This goes to what I’m asking here:

In what circumstances would such an attribute be more ergonomic/useful around a _use_ site rather than an _import_ site?

And if _use_ site annotations are the preferred design, when is a _scope-by-scope_ setting the way to go, versus a _line-by-line_ or _file-by-file_ annotation?

Is there a role for an _import_-site annotation in addition to use-site annotations? Is there a role for a _module-by-module_ flag if there are use site annotations?

My personal bias is that, in the WebKit example, supporting only an import-site annotation appears to be the simplest for both the user and the language. Users of the deprecated feature will be calling those APIs in multiple scopes, and it would not be ergonomic to have scope-by-scope use-site annotations, nor would they want to ignore unrelated deprecation warnings across so much of their code. I’m not sure why this is considered to be overcomplicating?

---

<div class="post-metadata">

**Author:** ![NSXPCConnection](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nsxpcconnection/32/31019_2.png) [@NSXPCConnection](https://forums.swift.org/u/NSXPCConnection)\
**Post date:** [June 5, 2022, 4:56pm UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/25 "2022-06-05T16:56:41Z")

</div>

Take for example: you’re importing FooKit, FooKit is used extensively around the project however you may want to, for example, subclass your class from one of the FooKit classes but that class has no alternative unlike other deprecated symbols in FooKit, so you may want to attach the attribute to the subclass only. If you want an import based solution then fine, I’m writing one in the linked pr which should start working with a couple of changes. I just think that a scope based solution and an import based solution can work together, it doesn’t just have to be one

---

<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:** [June 5, 2022, 5:07pm UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/26 "2022-06-05T17:07:41Z")

</div>

> [@NSXPCConnection](#):
>
> Take for example: you’re importing FooKit, FooKit is used extensively around the project however you may want to, for example, subclass your class from one of the FooKit classes but that class has no alternative unlike other deprecated symbols in FooKit, so you may want to attach the attribute to the subclass only. If you want an import based solution then fine, I’m writing one in the linked pr which should start working with a couple of changes. I just think that a scope based solution and an import based solution can work together, it doesn’t just have to be one

Sure, two different ways of silencing deprecation warnings could work together, but does it hold its own weight—that is, is the second solution best for some set of usages, such that we would want it in addition to the first?

In this example, it seems you’d want to silence only `FooKit.DeprecatedClass`-related deprecation warnings in the file or files where you implement the subclass, which would be done with an attribute on `import class FooKit.DeprecatedClass`. To my mind, it would be less desirable to silence all deprecation warnings for anything implemented in the scope of your custom subclass (you’d probably want to be notified if you unintentionally called a deprecated UIKit method, for instance), which would be the function of attaching such an attribute to the subclass.

Is there another scenario you have in mind which benefits from use-site silencing of all deprecation warnings?

---

<div class="post-metadata">

**Author:** ![michelf](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/michelf/32/1180_2.png) [@michelf](https://forums.swift.org/u/michelf)\
**Post date:** [June 5, 2022, 5:26pm UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/27 "2022-06-05T17:26:16Z")

</div>

The `import` method seems to work well for modules and classes, but if instead you have a bunch of related methods or free functions that get deprecated it doesn't seem that straightforward, other than applying it to the whole module.

If the worry is that more deprecation warnings could appear in the future but would be silenced in those scopes, maybe we could have this:

```swift
@ignoreDeprecationWarnings(upTo: macOS 11)

```

Here, only deprecations done in macOS 11 and earlier would be silenced. If something else gets deprecated in macOS 12, the warning won't be silenced and you'll get notified.

* * *

Combined with my previous suggestion you could have:

```swift
@ignoreDeprecationWarnings(upTo: macOS 11, until: macOS 13)

```

It would silence deprecations made in macOS 11 and earlier, and they would reappear for macOS 13.

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [June 5, 2022, 6:52pm UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/28 "2022-06-05T18:52:57Z")

</div>

Big picture, I'd love to see the issue of 'necessary' uses of deprecated APIs solved, so I'm a big fan of the explorations in this thread.

> [@xwu](#):
>
> And if _use_ site annotations are the preferred design, when is a _scope-by-scope_ setting the way to go, versus a _line-by-line_ or _file-by-file_ annotation?

> [@NSXPCConnection](#):
>
> I just think that a scope based solution and an import based solution can work together, it doesn’t just have to be one

I think another important thing to keep in mind here when comparing potential solutions (if it hasn't already been mentioned up-thread somewhere), is that there is _legitimate value_ in deprecation warnings. Even more precisely, I see immense value in warnings about _newly deprecated_ declarations when libraries are updated. It may very well be the case that at the time of importing `FooKit`, I feel comfortable about ignoring all the deprecated APIs, but I don't know if we should provide a way for users to easily express "I will _never_ care about any deprecated APIs in the future".

_ETA: Another way of phrasing what I'm trying to get at is that while a blanket "ignore all deprecation warnings" compiler flag, import/scope annotation, etc., might **seem** to be to the benefit of users, it might actually do more harm than good, and I think that it is strictly **worse** for library developers who have an interest in making sure that their users are alerted in a timely manner about new deprecations_

The story of the danger I'm imagining, with both a scope-by-scope solution and an import-by-import solution looks like the following. I'm writing an app, using FooKit 1.0, which has various APIs, some deprecated from the 0.x days:

```swift
// FooKit
@available(*, deprecated, message: "No replacement, sorry!")
func myGreatFunc() {}

func myOtherFunc() {}

```

As an application developer, I really want to use `myGreatFunc()`, and I know it won't be going away any time soon, so I want to disable the deprecation warning (either so I can compile with warnings-as-errors, or keep warnings spam low, whatever). With coarser solutions, that might look like this

```swift
// MyApp

// import-based
@noDeprecationWarnings
import FooKit

// scope based
@noDeprecationWarnings
func useFooKit() {
  myGreatFunc()
  myOtherFunc()
}

```

One day, I decide to update to FooKit 2.0:

```swift
// FooKit
@available(*, deprecated, message: "No replacement, sorry!")
func myGreatFunc() {}

@available(*, deprecated, message: "This is inefficient, use myFixedOtherFunc!")
func myOtherFunc() {}

func myFixedOtherFunc() {}

```

Now, in the MyApp target, I would really have liked to get the deprecation warning for `myOtherFunc()`, but I won't! Sure, with the scope-based solution I _could have_ preemptively wrapped the call to `myGreatFunc()` in a separate scope, something like:

```swift
@noDeprecationWarnings
do {
  myGreatFunc()
}

```

but I _suspect_ most people wouldn't do that by default.

This pulls me toward a solution closer to "line-by-line", but I might even prefer something _more_ granular. Since deprecations are applied on a declaration-by-declaration basis, they should be disabled on a declaration-by-declaration basis. The solution in the FooKit example above would look something like:

```swift
func useFooKit() {
  #deprecated(myGreatFunc)()
  myOtherFunc()
}

```

This would apply anywhere you refer to a (deprecated) declaration:

```swift
class MySubclass: #deprecated(OldSuperclass) {
  func myMethod() {
    #deprecated(self.oldMethod)()
  }
}

```

In cases where you're using the deprecated declaration liberally, you would of course be free to _redeclare_ the declaration to 'undeprecate' it:

```swift
typealias OldSuperclass = #deprecated(FooKit.OldSuperclass)

extension OldSuperclass {
  func oldMethodFixed() {
    #deprecated(self.oldMethod)()
  }
}

```

This would fix all the cases where I've wanted to disable deprecation warnings, and I can't think of a situation where it wouldn't work (though please poke holes if you see any 🙂). I also really like that it mirrors the granularity at which deprecations are applied. IMO, the burden of local redeclaration for common uses of deprecated is not too high.

ETA:  
For an example of why I think even line-by-line is too coarse, consider (using syntax akin to `try`/`await`):

```swift
// FooKit

@available(*, deprecated, message: "No replacement, sorry!")
func myGreatFunc(_: Int) {}

@available(*, deprecated, message: "This is inefficient, use getAnIntFast!")
func getAnInt() -> Int {}

func getAnIntFast() -> Int {}

// MyApp
func useFooKit() {
  // This ignores for myGreatFunc, but also getAnInt which we _do_ want a warning for!
  ignoreDeprecations myGreatFunc(getAnInt())
}

```

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [June 5, 2022, 11:45pm UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/29 "2022-06-05T23:45:51Z")

</div>

> **For greatest flexibility we can support silencing on all scopes.**
>
> ```swift
> // import scope
> @warning (deprecated=ignore)
> import FooKit
> 
> // type scope
> @warning (deprecated=ignore)
> struct Foo {
> }
> 
> // func / method scope
> @warning (deprecated=ignore)
> func foo() {
> }
> 
> // statement scope
> @warning (deprecated=ignore)
> if bar {
> }
> 
> // block of statements scope
> @warning (deprecated=ignore)
> do {
> let x = y()
> let x = t()
> }
> 
> // individual statement / declaration scope
> @warning (deprecated=ignore)
> let x = y
> 
> ```

Import scope is a bit too coarse for me (I may want to see the warnings in one file but not in another file, but AFAIK I can have a single import statement to import "FooKit" - in other words I am not forced to "import FooKit" in every file where I use it).

---

<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:** [June 6, 2022, 1:18am UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/30 "2022-06-06T01:18:03Z")

</div>

> [@tera](#):
>
> Import scope is a bit too coarse for me (I may want to see the warnings in one file but not in another file, but AFAIK I can have a single import statement to import "FooKit" - in other words I am not forced to "import FooKit" in every file where I use it).

In Swift, you are required to import `FooKit` in every file where you use it.

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [June 6, 2022, 11:09am UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/31 "2022-06-06T11:09:00Z")

</div>

> [@xwu](#):
>
> In Swift, you are required to import `FooKit` in every file where you use it.

I remember seeing counterexamples (and that was unexpected). Next time I see it - I will update this message.

---

<div class="post-metadata">

**Author:** ![hamishknight](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/hamishknight/32/14226_2.png) [@hamishknight](https://forums.swift.org/u/hamishknight)\
**Post date:** [June 6, 2022, 11:31am UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/32 "2022-06-06T11:31:33Z")

</div>

> [@tera](#):
>
> I remember seeing counterexamples (and that was unexpected). Next time I see it - I will update this message.

There are cases where extension members and conformances can be visible in files other than the one that imports them, however these are bugs:

- [[SR-3908] Extension methods visible without importing module in a file · Issue #46493 · swiftlang/swift · GitHub](https://github.com/apple/swift/issues/46493)
- [[SR-12984] Imported Protocol Conformance Leaks into Other Files · Issue #55430 · swiftlang/swift · GitHub](https://github.com/apple/swift/issues/55430)

---

<div class="post-metadata">

**Author:** ![Jon\_Shier](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jon_shier/32/921_2.png) [@Jon\_Shier](https://forums.swift.org/u/Jon_Shier)\
**Post date:** [June 6, 2022, 2:47pm UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/33 "2022-06-06T14:47:25Z")

</div>

Additionally, if you bridge in an Obj-C precompiled header, the modules visible in that header will become visible to Swift as well (at least, they did the last time I tried it).

---

<div class="post-metadata">

**Author:** ![millenomi](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/millenomi/32/2922_2.png) [@millenomi](https://forums.swift.org/u/millenomi)\
**Post date:** [June 8, 2022, 4:43pm UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/34 "2022-06-08T16:43:17Z")

</div>

Note that there are uses for silencing deprecation in a single module or in modules that are from the same source. A notable example is in swift-corelibs-foundation: we have several deprecated methods (eg: `Scanner.scanString(_:into:)`) that have modern replacements, but we need to keep around because our mandate is source compatibility. These methods have to be both called internally (eg. deprecated open methods someone may have overridden may need to be called to maintain execution invariants when the modern replacements are called on a subclass) and of course tested, opening a project to an avalanche of _its own_ deprecation warnings that are valid but cannot and should not be addressed at its internal or unit testing call sites.

(SCF specifically has a ton of warnings and the fact we cannot mark some as “this code is forever correct, trust me” makes dealing with the real ones that much harder and building with -Werror impossible.)

---

<div class="post-metadata">

**Author:** ![allevato](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/allevato/32/385_2.png) [@allevato](https://forums.swift.org/u/allevato)\
**Post date:** [June 8, 2022, 5:26pm UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/35 "2022-06-08T17:26:55Z")

</div>

> [@millenomi](#):
>
> Note that there are uses for silencing deprecation in a single module or in modules that are from the same source.

This is the issue that swift-protobuf has as well. When a field is declared as deprecated in the original .proto file, we'd like to mark it as deprecated in Swift, but the code internal to the generated type also gets/sets the field during serialization, and that would produce "false" deprecation warnings.

Doing something like public/private wrapping of the field could avoid this, but it's overhead that shouldn't be necessary IMO, so right now we just don't propagate the deprecation information.

[Previous discussions](https://forums.swift.org/t/pitch-omit-deprecation-warnings-for-same-file-references/5865) on this topic have led to some interesting ideas like visibility modifiers for deprecation (e.g., something can be declared as deprecated everywhere except the same file/the same module) and those would probably work for the situation @millenomi described, but those discussions didn't address having an escape hatch to suppress the warning if you need to use a deprecated declaration in a scope where it _was_ deprecated.

---

<div class="post-metadata">

**Author:** ![millenomi](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/millenomi/32/2922_2.png) [@millenomi](https://forums.swift.org/u/millenomi)\
**Post date:** [June 8, 2022, 7:05pm UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/36 "2022-06-08T19:05:42Z")

</div>

I'll be clear also that sometimes similar challenges can cross module boundaries, which is common in testing (where the unit test bundle is a separate module), or with frameworks factored into multiple modules (Foundation vs FoundationNetworking, for example).

---

<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:** [June 8, 2022, 9:14pm UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/37 "2022-06-08T21:14:46Z")

</div>

> [@allevato](#):
>
> This is the issue that swift-protobuf has as well. When a field is declared as deprecated in the original .proto file, we'd like to mark it as deprecated in Swift, but the code internal to the generated type also gets/sets the field during serialization, and that would produce "false" deprecation warnings.

Turning this around a bit, are there very many examples where self-deprecation warnings are “true positives” rather than nuisances?

A priori, it seems a library that’s grown enough complexity to “vend” to itself a distinct internal pseudo-API of enough history and stability that it actively relies on internal deprecation warnings is likely to want the compile-time benefits of true modularization.

I guess what I’m wondering is, would it make more sense to commit more fully to a design where deprecation is an API-level concern and disable self-deprecation warnings (at least by default).

> [@millenomi](#):
>
> I'll be clear also that sometimes similar challenges can cross module boundaries, which is common in testing (where the unit test bundle is a separate module), or with frameworks factored into multiple modules (Foundation vs FoundationNetworking, for example).

Would these use cases, in your experience, be ergonomically addressed by an attribute on the import statement that disables deprecation warnings on a file-by-file basis for that particular import? And, perhaps, if we do agree that deprecation is an API-level concern, having `@testable` imply `@_no_deprecation_warnings_strawman_spelling`?

---

<div class="post-metadata">

**Author:** ![NSXPCConnection](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nsxpcconnection/32/31019_2.png) [@NSXPCConnection](https://forums.swift.org/u/NSXPCConnection)\
**Post date:** [June 9, 2022, 9:45am UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/38 "2022-06-09T09:45:09Z")

</div>

Update: import support works with the implementation now as expected, so you can do

```swift
@ignoreDeprecationWarnings import deprecatedLib

func someFunc() {
   let s = someDeprecatedSymbol // no warnings because deprecatedLib was imported with `@ignoreDeprecatedWarnings`
}

```

---

<div class="post-metadata">

**Author:** ![NSXPCConnection](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nsxpcconnection/32/31019_2.png) [@NSXPCConnection](https://forums.swift.org/u/NSXPCConnection)\
**Post date:** [June 9, 2022, 12:08pm UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/39 "2022-06-09T12:08:42Z")

</div>

@xwu Thoughts on a compiler flag so this can be done project-wide?

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [June 9, 2022, 12:23pm UTC](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791/40 "2022-06-09T12:23:54Z")

</div>

I continue to think it will be an attractive nuisance to offer mechanisms for users to wholesale ignore deprecation warnings at the import or project level, with the possible exception of the ‘self-deprecation’ issues mentioned above—I’d be fine with offering a compiler flag to ignore internal deprecation warnings, and I think it’s probably a good idea to have `@testable` imply the suppression of deprecation warnings.

But outside of those narrow cases, I think it’s actively undesirable to allow users to _easily_ silence such warnings without thinking about specific deprecations. It seems super easy to do this in a non-forward-looking manner, and then accidentally find yourself wishing you hadn’t applied the suppression so widely when an API is unexpectedly ripped out from under you. _Each_ deprecation should require _explicit acknowledgement_ from clients before they’re able to use it without warning. Otherwise, library developers can no longer rely on deprecation as a reliable way to soften the transition to new APIs.

For users who _really_ want to silence _every_ deprecation warning, I’m really fine with requiring them to define a _MyApp+Undeprecations.swift_ file where they redeclare, typealias, and extend away each deprecation warning individually. That seems to me like a fair balance to strike.

[Previous page](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791.md?page=1)

[Next page](https://forums.swift.org/t/pitch-attribute-to-silence-deprecation-warnings-for-a-specified-scope/57791.md?page=3)
