instance visibility (was: Re: The base library and GHC 6.10)
Simon Marlow
marlowsd at gmail.com
Wed Sep 24 10:59:12 EDT 2008
(sorry for the delay in replying to this...)
Claus Reinke wrote:
>> This raises the more general issue of instance-visibility. Since
>> instances are automatically re-exported and therefore break
>> abstraction barriers, the only sensible way to think about instances
>> is as global properties.
>
> I've heard this fatalistic view expressed before, and even for
> impoverished Haskell 98, it just isn't true. Perhaps it has come about
> from years of being bitten by either #2182, by attempts
> to avoid "orphan" instances, by carelessly designed libraries, or
> by careless instance imports, all of which make combining libraries
> that provide instances of the same class for the same type a pain?
No, it has nothing to do with bugs or misfeatures in GHC, it's a fact of
Haskell 98.
> A type class specifies a relation between types. Both the types
> and the class are named, and if instances are placed in separate
> modules, the modules are named as well. The combination of
> module, class and type names gives quite a bit of control over instance
> import/export, even if it is terribly cumbersome and
> limited (and easily defeated by just one library importing all
> instances "for convenience"). Neither the relation (class), nor
> its domain (types), nor its extent (instances) are "global".
The point is that instances are unconditionally re-exported, which
exposes knowledge about the import structure underneath a module. If we
consider instances to be part of the API of a module, then the API of a
module is changed simply by changing what is imported. This is clarly
an abstraction failure, because we want a module to be able to control
its API independently of its implementation.
This is even worse at the level of packages. We can hide modules that
are used internally to a package's implementation, but we can't hide the
fact that a package used some non-standard instances internally, and
furthermore we can't change this aspect of its implementation without
changing the API.
So thinking of instances as part of the API of a module is wrong,
because it leads to the aforementioned abstraction failures. The only
sensible way to think of instances is as global properties - one
instance per class/type pair.
Orphan instances are usually wrong unless the orphans are also exported
via the standard API for either the class or the type. That is, orphans
are ok in the implementation of a package, but not in the exposed API,
because that makes it possible for a client to import both the class and
type without getting the instance, which is what we have to avoid.
Cheers,
Simon
More information about the Libraries
mailing list