Generic type class has type family; leads to big dep_finsts
While trying to determine a good explanation for simonpj's question in D2607, I noticed that dep_finsts
was a lot larger than I would have ordinarily expected it to be: it included many modules that did not have the TypeFamilies
extension enabled for them. For example, for one module in Cabal, here's "family instance modules":
family instance modules: Distribution.Compat.Semigroup
Distribution.Compiler Distribution.ModuleName Distribution.Package
Distribution.Simple.Compiler Distribution.System
Distribution.Utils.ShortText Distribution.Verbosity
Distribution.Version Language.Haskell.Extension Control.Applicative
Data.Complex Data.Either Data.Functor.Const Data.Functor.Identity
Data.List.NonEmpty Data.Monoid Data.Semigroup Data.Type.Equality
Data.Version Data.Void GHC.Exts GHC.Generics GHC.IO.Exception
GHC.TypeLits Data.IntMap.Base Data.IntSet.Base Data.Map.Base
Data.Sequence Data.Set.Base Text.PrettyPrint.Annotated.HughesPJ
Text.PrettyPrint.HughesPJ
Do we *really* have this many type family instances in base and Cabal? I was flummoxed, until I realized that the Generic type class defines a type family!
-- | Representable types of kind *.
-- This class is derivable in GHC with the DeriveGeneric flag on.
class Generic a where
-- | Generic representation type
type Rep a :: * -> *
-- | Convert from the datatype to its representation
from :: a -> (Rep a) x
-- | Convert from the representation to the datatype
to :: (Rep a) x -> a
The upshot is that if you derive Generic, you have agreed to a perpetual interface file size tax on every module which transitively depends on your module, as well as lots of fruitless pairwise consistency checking. Ick, especially considering that it's fairly common practice to slap a Generic on every data type you define.
This is a case where we would gain a lot if we could put a local restriction on Generic instances so that individual instances are guaranteed not to overlap, e.g., like one of the rules that Rust uses (http://smallcultfollowing.com/babysteps/blog/2015/01/14/little-orphan-impls/) Then we'd avoid balling up a big transitive closure of all modules that wrote deriving Generic
. Since non-overlapness is guaranteed by construction, we'd no longer need an eager check.
Related #5224
Trac metadata
Trac field | Value |
---|---|
Version | 8.1 |
Type | Bug |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Compiler |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | goldfire, simonpj |
Operating system | |
Architecture |