Don’t throw an error (by default) for use of DEPRECATED symbols under -Werror
Summary
Overview
Don’t throw an error by default under -Werror
when a DEPRECATED
module, function, or type is imported or used. Use or import of a module, function, or type marked with the WARNING
pragma will still be promoted to an error under -Werror
.
The Idea
Some “warnings” are more what you would consider “information” and should not be considered “errors” under -Werror
(unless explicitly requested).
Motivation
Consider you’re the maintainer of a widely used library and you wish to remove some function in some later release. There is currently no way of communicating to users of your library that you plan to remove this symbol in some later major release. The natural way to express this would be to add a DEPRECATED
pragma to the function in the next minor release, leave it there for some time horizon, and then in a following major release remove the symbol. This currently is not practical because a very large number of projects that use your library compile with -Werror
which will then cause builds to fail //simply because you tried to alert your users of future plans//. I posit that this is broken, the crux of this is that a DEPRECATED
//should// be considered as //info// and not a true //warning//.
As it stands today, **two major releases** are required to safely deprecate (and remove) part of a public API due to the wide usage of -Werror
which causes build failures when a new DEPRECATED pragma is added. The first major release adds the DEPRECATED pragma and the second removed the symbol or module. This discourages deprecating old APIs, introduces unnecessary version churn, and makes it more difficult to communicate to consumers of a library that an upcoming release will remove a feature.
As a specific example, when attempting to align the public APIs of containers
and unordered-containers
(renaming HashMap.lookupDefault
to HashMap.findWithDefault
to match the API of containers
) the largest issue was how to actually deprecate the old function. The unordered-containers
API is relatively stable and it wouldn’t warrant a new major version just to mark a function as DEPRECATED
. You can see the discussion here (http://haskell.1045720.n5.nabble.com/Proposal-Rename-HashMap-lookupDefault-to-HashMap-findWithDefault-td5870348.html).
= Changes
== Flag Changes
- *Before**
-Wdeprecations
- warn if a module, function, or type marked DEPRECATED
or WARNING
is imported or used.
-Wwarnings-deprecations
- warn if a module, function, or type marked DEPRECATED
or WARNING
is imported or used. (The name of this flag is unfortunate, imho it should be named -Wwarnings
)
-Werror
- promote warnings to errors, including both -Wdeprecations
and -Wwarnings
. In other words, if a DEPRECATED
or WARNING
module, function, or type is imported or used.
Note that //currently// there is **no distinction** between things marked as WARNING
and things marked as DEPRECATED
at the flag level, this is problematic.
- *After**
-Wdeprecations
- warn if a module, function, or type marked DEPRECATED
is imported or used.
-Wwarnings-deprecations
(or rename to -Wwarnings
) - warn if a function, module, or type marked WARNING
is imported or used.
-Werror
- promote warnings to errors, including -Wwarnings-deprecations
(WARNING
), **but not** -Wdeprecations
(DEPRECATED
).
(optional) -Wwarnings
- warn if a function, module, or type marked WARNING
is imported or used. This is a clearer flag name than -Wwarnings-deprecations
.
Precedent for excluding warnings from being promoted to errors
The idea that some things considered “warnings” are not actually “errors” already exists, specifically the flag -Wmissed-specialisations
(https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/using-warnings.html#ghc-flag--Wmissed-specialisations) is already excluded from the set of warnings that are not considered as errors.
How do I get the old behaviour back? aka. treat DEPRECATED as an error
If you’re using a library and you’d like to be extra up to date and cause your build to fail if you’re using a deprecated function then you can pass -Werror=deprecations
to GHC and it will treat use of DEPRECATED
as an error.
Alternatives Considered
No change (baseline)
The current state of the world as discussed in the //Motivation// section causes real issues related to natural evolution of APIs. I feel that this is not desirable in the long term.
DEPRECATED
from -Werror
Ask people to exclude Another option is to ask folks to not treat deprecations as errors by explicitly passing -Wwarn=deprecations
(still requires changes to GHC since WARNING
and DEPRECATED
are grouped together currently). This would “fix” the problem but makes the assumption that everyone updates their build flags appropriately which is an incredibly unreasonable assumption. It also doesn’t actually address the core problem of use of deprecated APIs being treated as erroneous.
Related Work/Proposals
There is an open PR to the PVP to no longer require a major version bump when a DEPRECATED
pragma is added which has received support from both the community and members of the CLC (https://github.com/haskell/pvp/pull/18) and follows the same reasoning as here, namely that deprecating something is not meant to (and should not) break anything since it doesn’t change the API, it simply provides some information to users of the library.
Example Implementation
I've put together a possible implementation of this at !89, but please do not comment on design there, keep that in the trac issue here.