1 Deprecated instances¶
GHC allows to deprecate modules, functions, data constructors, type
constructors, but not instances. The lack of support for deprecation of
instances makes it impossible to remove them gracefully, with an advance
warning to the users. We propose to allow {-# WARNING ... #-}
and
{-# DEPRECATED ... #-}
pragmas on instances to correct this.
1.1 Background¶
GHC already allows library authors to deprecate modules, functions, data constructors, and type constructors (including data types, newtypes, type synonyms, type families, data families, and classes).
Here is an example of a deprecated module:
module M {-# DEPRECATED "Do not use M" #-} where
Importing M
produces the following warning:
Example.hs:3:1: warning: [-Wdeprecations]
Module ‘M’ is deprecated: "Do not use M"
And here is an example of a deprecated function:
{-# DEPRECATED f "Do not use f" #-}
f :: Int -> Int
f = id
Using f
produces the following warning:
Example.hs:5:5: warning: [-Wdeprecations]
In the use of ‘f’ (imported from M): Deprecated: "Do not use f"
Library authors use deprecation warnings to great effect.
Searching Hackage for {-# DEPRECATED
results in
3024 matches across 656 packages.
1.2 Motivation¶
Discussions at deepseq #16 “remove instance NFData (a -> b)”
and bytestring #140 “Surprising behavior of ByteString literals via IsString”
reveal that there is demand for deprecation warnings on instances,
which are currently not supported.
The goal is to inform the users that the instance should be avoided
before removing it outright or rendering it unusable via a TypeError
constraint.
Functions, data constructors and type constructors are referenced by name in deprecation pragmas. This is not an option for instances, as instances are anonymous.
Modules use inline deprecation pragmas right before the where
keyword.
An attempt to add an inline pragma to an instance leads to a parse error:
-- Code:
data T
instance {-# DEPRECATED "Do not use Eq T" #-} Eq T where
-- Error message:
Example.hs:2:10: error: parse error on input ‘{-# DEPRECATED’
We propose to allow inline deprecation pragmas on instances.
The {-# WARNING ... #-}
pragma is a close sibling of {-# DEPRECATED ... -}
, so we propose to allow it too.
1.3 Proposed Change Specification¶
1.3.1 Syntax¶
The existing non-terminals in Parser.y
are defined thus:
maybemodwarning
: '{-# DEPRECATED' strings '#-}'
| '{-# WARNING' strings '#-}'
| {- empty -}
inst_decl
: 'instance' overlap_pragma inst_type where_inst
| ...
stand_alone_deriving
: 'deriving' deriv_standalone_strategy 'instance' overlap_pragma inst_type
The maybemodwarning
is used in module headers. Rename it to maybewarning
and employ it in inst_decl
and stand_alone_deriving
as follows:
inst_decl
: 'instance' maybewarning overlap_pragma inst_type where_inst
| ...
stand_alone_deriving
: 'deriving' deriv_standalone_strategy 'instance' maybewarning overlap_pragma inst_type
1.3.2 Semantics¶
When GHC solves a constraint using an instance marked with a
{-# DEPRECATED ... #-}
or a {-# WARNING ... #-}
pragma,
it reports the attached warning.
The rules for instance matching are given in section 6.8.8 “Instance declarations and resolution” of the User’s Guide.
1.4 Examples¶
The notorious NFData
instance can be modified as follows:
instance {-# DEPRECATED "Do not use NFData (a -> b). See deepseq issue #16" #-}
NFData (a -> b)
where
rnf = rwhnf
With this change, any use of the NFData (a -> b)
instance,
be it explicit in user-written code or generated by Generic
-based deriving,
will result in a deprecation warning.
1.5 Effect and Interactions¶
We have tested and confirmed that the syntax changes do not lead to any shift/reduce or reduce/reduce conflicts. The proposed syntax is easy to parse.
The proposal is restricted to class instances and does not cover type family or data family instances. While it is trivial to extend the syntax, the semantics are less clear and we do not have concrete motivating examples.
1.6 Costs and Drawbacks¶
We expect the implementation and maintenance costs for this feature to be minimal.
1.7 Alternatives¶
An alternative, constraint-based approach, is presented in #454. The pragma-based approach proposed here is more conservative and easier to implement.
We could allow instance pragmas to come in arbitrary order and in postfix positions. The most general syntax would look like this:
instance_pragmas : instance_pragmas warning_pragma | instance_pragmas overlap_pragma | {- empty -} inst_decl : 'instance' instance_pragmas inst_type instance_pragmas where_inst | ... stand_alone_deriving : 'deriving' deriv_standalone_strategy 'instance' instance_pragmas inst_type instance_pragmas
We choose not to do this for the sake of simplicity and to limit the scope of the proposal, but it is conceivable that a future proposal might introduce the more general syntax.
1.8 Implementation Plan¶
Bartłomiej Cieślar intends to implement this as part of his internship at IOG.