RE: [nightly] 10-Aug-2008 build of HEAD on i386-unknown-linux (cam-02-unx.europe.corp.microsoft.com)

| -fgenerics -Wall -fno-warn-deprecated-flags -c Data/Time/Calendar/Gregorian.hs -o | dist/build/Data/Time/Calendar/Gregorian.o -ohi dist/build/Data/Time/Calendar/Gregorian.hi | | Data/Time/Calendar/Gregorian.hs:73:9: | Warning: orphan instance: instance Show Day | | <no location info>: | Failing due to -Werror. | | gmake[2]: *** [dist/build/Data/Time/Calendar/Gregorian.o] Error 1 | gmake[2]: Leaving directory `/playpen/simonmar/nightly/HEAD/i386-unknown-linux/libraries/time' | gmake[1]: *** [make.library.time] Error 2 | gmake[1]: Leaving directory `/playpen/simonmar/nightly/HEAD/i386-unknown-linux/libraries' | gmake: *** [stage1] Error 2 Now that orphan warnings are "proper warnings" as Duncan requested, and hence do the right thing with -Werror, someone should either remove this orphan (best), by moving the instance to the module that defines Day, or add -fno-warn-orphans to this module. Who is responsible for the time/ library? There may be other libraries similarly affected. Simon

On Mon, 2008-08-11 at 08:25 +0100, Simon Peyton-Jones wrote:
| Data/Time/Calendar/Gregorian.hs:73:9: | Warning: orphan instance: instance Show Day | | <no location info>: | Failing due to -Werror. | | gmake[2]: *** [dist/build/Data/Time/Calendar/Gregorian.o] Error 1 | gmake[2]: Leaving directory `/playpen/simonmar/nightly/HEAD/i386-unknown-linux/libraries/time' | gmake[1]: *** [make.library.time] Error 2 | gmake[1]: Leaving directory `/playpen/simonmar/nightly/HEAD/i386-unknown-linux/libraries' | gmake: *** [stage1] Error 2
Now that orphan warnings are "proper warnings" as Duncan requested, and hence do the right thing with -Werror,
Thank you :-)
someone should either remove this orphan (best), by moving the instance to the module that defines Day, or add -fno-warn-orphans to this module.
Who is responsible for the time/ library?
Author: Ashley Yakeley
Maintainer:
There may be other libraries similarly affected.
I think we should not build the non-core libs with -Werror. It makes perfect sense for the core libs where the ghc team effectively maintains them, but not for non-core ones. It is for exactly this reason that hackage rejects packages that specify "ghc-options: -Werror"; new compiler warnings make old packages fail to compile. So there should not be many libraries affected (there are only one or two on hackage that use -Werror before we added the check to reject it). So the packages themselves don't specify -Werror. I assume it's just ghc's build system adds it for all libs, core and other. Duncan

| I think we should not build the non-core libs with -Werror. It makes | perfect sense for the core libs where the ghc team effectively maintains | them, but not for non-core ones. But time *is* a core lib. Similarly containers, pretty, filepath, directory... The full list is below. GHC is simply a client for these libraries. Should they have -Werror or not? I'm not sure. Simon | | It is for exactly this reason that hackage rejects packages that specify | "ghc-options: -Werror"; new compiler warnings make old packages fail to | compile. So there should not be many libraries affected (there are only | one or two on hackage that use -Werror before we added the check to | reject it). So the packages themselves don't specify -Werror. I assume | it's just ghc's build system adds it for all libs, core and other. | | Duncan utils/hsc2hs hsc2hs libraries/array packages/array libraries/base packages/base libraries/bytestring packages/bytestring libraries/Cabal packages/Cabal libraries/containers packages/containers libraries/directory packages/directory libraries/editline packages/editline libraries/filepath packages/filepath libraries/ghc-prim packages/ghc-prim libraries/haskell98 packages/haskell98 libraries/hpc packages/hpc libraries/integer-gmp packages/integer-gmp libraries/old-locale packages/old-locale libraries/old-time packages/old-time libraries/packedstring packages/packedstring libraries/pretty packages/pretty libraries/process packages/process libraries/random packages/random libraries/template-haskell packages/template-haskell libraries/unix packages/unix libraries/Win32 packages/Win32

On Mon, 2008-08-11 at 12:27 +0100, Simon Peyton-Jones wrote:
| I think we should not build the non-core libs with -Werror. It makes | perfect sense for the core libs where the ghc team effectively maintains | them, but not for non-core ones.
But time *is* a core lib. Similarly containers, pretty, filepath, directory... The full list is below.
That list indicates that "old-time" is a core lib but "time" is not.
GHC is simply a client for these libraries. Should they have -Werror or not? I'm not sure.
I'm not sure either for those core libs that have external maintainers like filepath etc, but for non-core like "time" it'd be much easier for you without -Werror.
utils/hsc2hs hsc2hs libraries/array packages/array libraries/base packages/base libraries/bytestring packages/bytestring libraries/Cabal packages/Cabal libraries/containers packages/containers libraries/directory packages/directory libraries/editline packages/editline libraries/filepath packages/filepath libraries/ghc-prim packages/ghc-prim libraries/haskell98 packages/haskell98 libraries/hpc packages/hpc libraries/integer-gmp packages/integer-gmp libraries/old-locale packages/old-locale libraries/old-time packages/old-time
but no "time"
libraries/packedstring packages/packedstring libraries/pretty packages/pretty libraries/process packages/process libraries/random packages/random libraries/template-haskell packages/template-haskell libraries/unix packages/unix libraries/Win32 packages/Win32
Duncan

| I think we should not build the non-core libs with -Werror. It makes | perfect sense for the core libs where the ghc team effectively maintains | them, but not for non-core ones.
But time *is* a core lib. Similarly containers, pretty, filepath, directory... The full list is below. GHC is simply a client for these libraries. Should they have -Werror or not? I'm not sure.
The first time I joined a project with rcs (and in those days, that meant RCS), I was given a few firm rules, the most important of which was (emphasis added): 1. whatever I check in, the _whole_ thing has to build ok An immediate corollary was: 2. if _my_ changes break someone else's code, _I_ have to fix that In these days of distributed rcs with one build using multiple repos or even multiple rcss, those rules aren't as clear, but I'd suggest to interpret GHC+corelibs as a unit, and to apply rules 1 and 2. In fact, until the Haskell Platform is ready to take over from extralibs, it would be helpful to apply the same rules to extralibs as well. Otherwise, we'll end up here ? It highlights an important advantage of having a nontrivial set ? of extralibs in the ghc buildbot: early warnings about when and ? how ghc changes are going to break user-/library-code. ? ? Once the extralibs go, that feedback will be less immediate, the ? spread of breakage will be wider, and the current "why should ? Ghc Hq have to worry about network package maintenance?" ? could easily turn into a major source of friction, with both Ghc ? Hq and library maintainers insisting that the breakage isn't in their ? boat ("but HEAD fast builds just fine","but I didn't change a bit ? in my library code") and users likely to pay the price. much faster than even I feared just a week ago.. Claus ps. so that you don't have to iterate over failures: http://www.haskell.org/pipermail/cvs-ghc/2008-August/044021.html

On Mon, Aug 11, 2008 at 12:16:08PM +0100, Duncan Coutts wrote:
Who is responsible for the time/ library?
I think we should not build the non-core libs with -Werror.
We don't, but: $ head -1 time/Data/Time/Calendar/Gregorian.hs {-# OPTIONS -Wall -Werror #-} (in actual fact, we don't even build GHC/bootlibs with -Werror except when validating). Thanks Ian

On Tue, 2008-08-12 at 00:33 +0100, Ian Lynagh wrote:
On Mon, Aug 11, 2008 at 12:16:08PM +0100, Duncan Coutts wrote:
Who is responsible for the time/ library?
I think we should not build the non-core libs with -Werror.
We don't, but:
$ head -1 time/Data/Time/Calendar/Gregorian.hs {-# OPTIONS -Wall -Werror #-}
(in actual fact, we don't even build GHC/bootlibs with -Werror except when validating).
Ah, so that's the culprit. Duncan

Duncan Coutts wrote:
$ head -1 time/Data/Time/Calendar/Gregorian.hs {-# OPTIONS -Wall -Werror #-}
(in actual fact, we don't even build GHC/bootlibs with -Werror except when validating).
Ah, so that's the culprit.
I prefer this, actually, as we get to discover issues sooner rather than later. Though putting it in the .cabal file or wherever might be better. It makes sense for Hackage to reject packages that use -Wall -Werror, but for that I use a Makefile that calls cabal passing them in. -- Ashley Yakeley

Ashley | Duncan Coutts wrote: | >> $ head -1 time/Data/Time/Calendar/Gregorian.hs | >> {-# OPTIONS -Wall -Werror #-} | >> | >> (in actual fact, we don't even build GHC/bootlibs with -Werror except | >> when validating). | > | > Ah, so that's the culprit. | | I prefer this, actually, as we get to discover issues sooner rather than | later. Though putting it in the .cabal file or wherever might be better. That's fine. But then you can choose a) add -fno-warn-orphans or b) move the (Show Day) instance to the module declaring Day. I'm not sure which is best for you, but you're the package author so you get to decide! Regardless, it'd help if you felt able to do one or the other, because currently the package won't compile at all. Simon

Simon Peyton-Jones wrote:
That's fine. But then you can choose
a) add -fno-warn-orphans or b) move the (Show Day) instance to the module declaring Day.
I'm not sure which is best for you, but you're the package author so you get to decide!
Patch pushed. I've plumped for option a. It's better structuring, as b would involve moving more code from Gregorian.hs to Days.hs. The concern Henning raised shouldn't apply, as both modules are hidden and re-exported by Data.Time.Calendar. I've also fixed two other modules with the same issue (again, also hidden). -- Ashley Yakeley

| Patch pushed. I've plumped for option a. It's better structuring, as b | would involve moving more code from Gregorian.hs to Days.hs. | | The concern Henning raised shouldn't apply, as both modules are hidden | and re-exported by Data.Time.Calendar. I've also fixed two other modules | with the same issue (again, also hidden). Thanks. It doesn't matter whether they are hidden or not --- their instances are visible regardless in Haskell. So those interface files will be read any time you compile a module that depends on a module in the time package. But that's not a terribly big deal. Simon

Simon Peyton-Jones wrote:
| Patch pushed. I've plumped for option a. It's better structuring, as b | would involve moving more code from Gregorian.hs to Days.hs. | | The concern Henning raised shouldn't apply, as both modules are hidden | and re-exported by Data.Time.Calendar. I've also fixed two other modules | with the same issue (again, also hidden).
Thanks. It doesn't matter whether they are hidden or not --- their instances are visible regardless in Haskell. So those interface files will be read any time you compile a module that depends on a module in the time package. But that's not a terribly big deal.
What I meant was, the module in which the instance is defined, and the module in which the type is defined are both hidden, and only re-exported by another module. Thus it is not possible to import the type without importing the instance. I believe this is the concern that Henning Thielemann raised. -- Ashley Yakeley

On Tue, Aug 12, 2008 at 12:54:04AM -0700, Ashley Yakeley wrote:
What I meant was, the module in which the instance is defined, and the module in which the type is defined are both hidden, and only re-exported by another module. Thus it is not possible to import the type without importing the instance.
Not quite: * Data.Time.Calendar exports Day without its Read instance. * Data.Time.Clock exports UTCTime without Read or Show instances. * Data.Time.LocalTime exports TimeOfDay, LocalTime, TimeZone, UTCTime and ZonedTime without Read instances.

I'm not sure which is best for you, but you're the package author so you get to decide!
While you're looking at the code for time, Ashley, I've got a question about its relation to old-time: shouldn't System.Time have a DEPRECATED pragma, pointing to time? The comments and package name say old-time is deprecated in favour of time. Claus

On Tue, 2008-08-12 at 10:30 +0100, Claus Reinke wrote:
I'm not sure which is best for you, but you're the package author so you get to decide!
While you're looking at the code for time, Ashley, I've got a question about its relation to old-time: shouldn't System.Time have a DEPRECATED pragma, pointing to time? The comments and package name say old-time is deprecated in favour of time.
Probably. I've never touched old-time. -- Ashley Yakeley

Claus Reinke wrote:
I'm not sure which is best for you, but you're the package author so you get to decide!
While you're looking at the code for time, Ashley, I've got a question about its relation to old-time: shouldn't System.Time have a DEPRECATED pragma, pointing to time? The comments and package name say old-time is deprecated in favour of time.
I looked into this; it's not quite that simple. System.Time exports ClockTime, which is still used in System.Directory.getModificationTime. So in order to properly deprecate System.Time, we have to supply an alternative to System.Directory.getModificationTime, which would introduce a dependency on the time package, and directory is currently a core package. Cheers, Simon

While you're looking at the code for time, Ashley, I've got a question about its relation to old-time: shouldn't System.Time have a DEPRECATED pragma, pointing to time? The comments and package name say old-time is deprecated in favour of time.
I looked into this; it's not quite that simple. System.Time exports ClockTime, which is still used in System.Directory.getModificationTime. So in order to properly deprecate System.Time, we have to supply an alternative to System.Directory.getModificationTime, which would introduce a dependency on the time package, and directory is currently a core package.
Thanks for checking, Simon. But wouldn't that simply mean replacing old-time with time in the corelibs, keeping old-time around for one or two releases only to get the deprecation message out? Perhaps time could even provide a compat module for the transition period, so that old-time could be dropped immediately, while current old-time clients transition from the compat module to proper time modules. Claus

Claus Reinke wrote:
While you're looking at the code for time, Ashley, I've got a question about its relation to old-time: shouldn't System.Time have a DEPRECATED pragma, pointing to time? The comments and package name say old-time is deprecated in favour of time.
I looked into this; it's not quite that simple. System.Time exports ClockTime, which is still used in System.Directory.getModificationTime. So in order to properly deprecate System.Time, we have to supply an alternative to System.Directory.getModificationTime, which would introduce a dependency on the time package, and directory is currently a core package.
Thanks for checking, Simon. But wouldn't that simply mean replacing old-time with time in the corelibs, keeping old-time around for one or two releases only to get the deprecation message out? Perhaps time could even provide a compat module for the transition period, so that old-time could be dropped immediately, while current old-time clients transition from the compat module to proper time modules.
I don't think it's straightforward to implement System.Time in terms of Data.Time, so we really have to bring in time. Also, we have to replace System.Directory.getModificationTime (I suppose it should return UTCTime?), and hence we'll need a compat version of directory... or call the new function something different. Cheers, Simon

Simon Peyton Jones wrote:
| Data/Time/Calendar/Gregorian.hs:73:9: | Warning: orphan instance: instance Show Day | [...]
Now that orphan warnings are "proper warnings" as Duncan requested, and hence do the right thing with -Werror, someone should either remove this orphan (best), by moving the instance to the module that defines Day,
I just would like to point out that there is nothing inherently bad about what GHC calls ``orphan instances''. From a code structuring point of view, I frequently ``consider orphan'' instances useful for separation of concerns. Just consider a simple, prelude-based example: Read instances tend to pull in dependencies (e.g. Parsec) that a new datatype as such does not need, and the new datatyps's Read instance is also not needed everywhere where the type is needed itself. So I frequently create MyDatatypeRead modules with explicit, empty export lists, to export only the (``orphan'') instance. Orphan warnings are only an implementation-specific hint about an implementation-specific problem --- checking the GHC user manual again, I find that ``GHC tries to be clever'', and ``orphan instances'' are documented as only a situation that prolongs compile time.
or add -fno-warn-orphans to this module.
I have no problem with this (of course I would consider using a OPTIONS_GHC pragma the preferable way); I just would like to emphasise that there is no implementation-independent reason to avoid ``orphan instances''. (On the implementation side, a completely different solution would be to add (automatically) re-exported instances (and rewrite rules) to the export lists stored inside .hi files --- then ``orphan instances'' would be no worse than other instances.) Wolfram

On Tue, 12 Aug 2008 kahl@cas.mcmaster.ca wrote:
I just would like to point out that there is nothing inherently bad about what GHC calls ``orphan instances''.
From a code structuring point of view, I frequently ``consider orphan'' instances useful for separation of concerns.
The problem is, that if you have a main instance of a class for a type and this one is not bundled with either the type or the class, then you are able to import the type and the class without the main instance (that is, you can accidentally miss that instance), and thus you are able to define another instance. This will likely cause clash with the main instance sooner or later, if other modules import your custom instance and the main one.

Henning Thielemann
On Tue, 12 Aug 2008 kahl@cas.mcmaster.ca wrote:
I just would like to point out that there is nothing inherently bad about what GHC calls ``orphan instances''.
From a code structuring point of view, I frequently ``consider orphan'' instances useful for separation of concerns.
The problem is, that if you have a main instance of a class for a type and this one is not bundled with either the type or the class, then you are able to import the type and the class without the main instance (that is, you can accidentally miss that instance)
Or on purpose --- this is in fact another use of ``orphan instances'' I forgot to mention.
, and thus you are able to define another instance.
Indeed --- this is the only way to have different instances for the same class, as long as we do not have something like the ``named instances'' of our Haskell-2001 paper (shameless plug ;-).
This will likely cause clash with the main instance sooner or later, if other modules import your custom instance and the main one.
If there are several instances, there is very likely no ``main instance''. Wolfram

On Tue, 2008-08-12 at 17:38 +0000, kahl@cas.mcmaster.ca wrote:
Henning Thielemann
wrote: On Tue, 12 Aug 2008 kahl@cas.mcmaster.ca wrote:
I just would like to point out that there is nothing inherently bad about what GHC calls ``orphan instances''.
From a code structuring point of view, I frequently ``consider orphan'' instances useful for separation of concerns.
The problem is, that if you have a main instance of a class for a type and this one is not bundled with either the type or the class, then you are able to import the type and the class without the main instance (that is, you can accidentally miss that instance)
Or on purpose --- this is in fact another use of ``orphan instances'' I forgot to mention.
, and thus you are able to define another instance.
Indeed --- this is the only way to have different instances for the same class, as long as we do not have something like the ``named instances'' of our Haskell-2001 paper (shameless plug ;-).
This will likely cause clash with the main instance sooner or later, if other modules import your custom instance and the main one.
If there are several instances, there is very likely no ``main instance''.
If there is no main instance, there should very likely be no instance at all. We already have named instances: data ShowDict alpha = ShowDict alpha { namedShows :: alpha -> String -> String } show :: ?namedShow :: ShowDict alpha => alpha -> String show x = namedShows ?namedShow x "" Confusing this with type classes seems mostly redundant to me. jcc

Wolfram wrote:
Or on purpose --- this is in fact another use of ``orphan instances'' I forgot to mention... Indeed --- this is the only way to have different instances for the same class, as long as we do not have something like the ``named instances'' of our Haskell-2001 paper (shameless plug ;-).
Henning Thielemann wrote:
This will likely cause clash with the main instance sooner or later, if other modules import your custom instance and the main one.
If there are several instances, there is very likely no ``main instance''.
Jonathan Cast wrote:
If there is no main instance, there should very likely be no instance at all. We already have named instances... Confusing this with type classes seems mostly redundant to me.
This argument, or something like it, is raised whenever someone mentions the need to define multiple instances of a class for the same type. And it is correct, theoretically. But in real life, you often need to write code against existing modules that you can't change. When an existing module exports an instance that is inconvenient, you can be in deep trouble. We are desperately in need of a solution to this problem. If not Wolfram's "named instances", then at least there must be some way to control the import and export of instances, just as we can now control the import and export of every other kind of symbol binding. Thanks, Yitz

On Wed, 13 Aug 2008, Yitzchak Gale wrote:
Jonathan Cast wrote:
If there is no main instance, there should very likely be no instance at all. We already have named instances... Confusing this with type classes seems mostly redundant to me.
This argument, or something like it, is raised whenever someone mentions the need to define multiple instances of a class for the same type. And it is correct, theoretically.
But in real life, you often need to write code against existing modules that you can't change. When an existing module exports an instance that is inconvenient, you can be in deep trouble.
We are desperately in need of a solution to this problem. If not Wolfram's "named instances", then at least there must be some way to control the import and export of instances, just as we can now control the import and export of every other kind of symbol binding.
For me it's most often the case that an instance is missing. If there is no way to change existing instance definitions, then you must use 'newtype'. Generalized newtype deriving simplifies to adapt the instances you want.

On 2008-08-12, Yitzchak Gale
Wolfram wrote:
Or on purpose --- this is in fact another use of ``orphan instances'' I forgot to mention... Indeed --- this is the only way to have different instances for the same class, as long as we do not have something like the ``named instances'' of our Haskell-2001 paper (shameless plug ;-).
Henning Thielemann wrote:
This will likely cause clash with the main instance sooner or later, if other modules import your custom instance and the main one.
If there are several instances, there is very likely no ``main instance''.
Jonathan Cast wrote:
If there is no main instance, there should very likely be no instance at all. We already have named instances... Confusing this with type classes seems mostly redundant to me.
This argument, or something like it, is raised whenever someone mentions the need to define multiple instances of a class for the same type. And it is correct, theoretically.
But in real life, you often need to write code against existing modules that you can't change. When an existing module exports an instance that is inconvenient, you can be in deep trouble.
Or, you can just use newtype. -- Aaron Denney -><-

We already have named instances:
data ShowDict alpha = ShowDict alpha { namedShows :: alpha -> String -> String }
This is not valid Haskell. Either all components of the data structure are named fields, or none. It is not possible to have a mixture of the two, as here. In addition, there are many classes it is not currently possible to simulate using this technique, because the types go significantly beyond Haskell'98. I believe you need both Rank-2 Types and Polymorphic Components to achieve comparable expressivity. Fuller details on the Haskell-Prime site: http://hackage.haskell.org/trac/haskell-prime/wiki/PolymorphicComponents Regards, Malcolm

On Wed, 2008-08-13 at 09:29 +0100, Malcolm Wallace wrote:
We already have named instances:
data ShowDict alpha = ShowDict alpha { namedShows :: alpha -> String -> String }
This is not valid Haskell.
I must have been distracted. I meant: data ShowDict alpha = ShowDict { namedShows :: alpha -> String -> String } obviously.
Either all components of the data structure are named fields, or none. It is not possible to have a mixture of the two, as here.
In addition, there are many classes it is not currently possible to simulate using this technique, because the types go significantly beyond Haskell'98.
My proposal already required implicit parameters... jcc

Simon Peyton-Jones wrote:
Who is responsible for the time/ library?
I am.
Now that orphan warnings are "proper warnings" as Duncan requested,
What is an orphan instance, and why do we care about them? Since they weren't proper warnings before, I always assumed they were some weird GHC thing and not any kind of a concern with the code. But apparently not? -- Ashley

| Ashley: | What is an orphan instance, and why do we care about them? They are documented in the GHC manual http://www.haskell.org/ghc/docs/latest/html/users_guide/separate-compilation... | Wolfram: | I just would like to point out that there is nothing inherently bad about | what GHC calls ``orphan instances''. ... that there is no *implementation-independent* | reason to avoid ``orphan instances''. | | From a code structuring point of view, | I frequently ``consider orphan'' instances | useful for separation of concerns. I agree. The warning just warns you that compilation of any module that depends on this module, or on the package of which this module becomes a part, will become a little slower, for reasons explained above. | (On the implementation side, a completely different solution would be | to add (automatically) re-exported instances (and rewrite rules) | to the export lists stored inside .hi files --- | then ``orphan instances'' would be no worse than other instances.) Indeed, you could certainly accumulate in every M.hi file a list of all orphan instances anywhere below M. What GHC does instead is to accumulate a list of all the *modules that contain* orphan instances, which amounts to much the same thing. Either way it's tiresome because all these instances must be brought into scope for every compilation, even though most of them are useless. As you say, though, it's just an implementation matter. That's why it's only a warning. Simon

Simon Peyton-Jones wrote:
| Ashley: | What is an orphan instance, and why do we care about them?
They are documented in the GHC manual http://www.haskell.org/ghc/docs/latest/html/users_guide/separate-compilation...
<cite> GHC identifies orphan modules, and visits the interface file of every orphan module below the module being compiled. This is usually wasted work, but there is no avoiding it. You should therefore do your best to have as few orphan modules as possible. </cite> [...]
I agree. The warning just warns you that compilation of any module that depends on this module, or on the package of which this module becomes a part, will become a little slower, for reasons explained above. [...] Indeed, you could certainly accumulate in every M.hi file a list of all orphan instances anywhere below M. What GHC does instead is to accumulate a list of all the *modules that contain* orphan instances, which amounts to much the same thing. Either way it's tiresome because all these instances must be brought into scope for every compilation, even though most of them are useless.
I still don't understand why ghc will become "slower" with orphaned modules. Where is "wasted work" or which "instances are useless"? Doesn't ghc just read all interface files of modules in the import chain (i.e. all modules "below")? Or is that the "disaster in practice, so GHC tries to be clever"? In what way is GHC clever? Are only interface files of directly imported modules (plus orphaned modules mentioned in there) read in? Is there a difference if I compile each file individually or if I use "ghc --make"? If I compile a single module M that does not need instances from an orphaned module, this orphaned module wouldn't be in the import chain and therefore I would expect the compilation of M to be faster. (Here I assume that I've only orphaned instances in orphaned modules.) Conversely, If all my instances are not orphaned I'll always have instances in scope that I may not need in some importing module. Could someone enlighten me? Cheers Christian

| I still don't understand why ghc will become "slower" with orphaned | modules. Where is "wasted work" or which "instances are useless"? | Doesn't ghc just read all interface files of modules in the import chain | (i.e. all modules "below")? Or is that the "disaster in practice, so GHC | tries to be clever"? In what way is GHC clever? Are only interface files | of directly imported modules (plus orphaned modules mentioned in there) | read in? In the *absence* of orphan modules, GHC reads as few interface files as possible. It must read the interface of every *directly-imported* module. After that, it's by-need only. For example module Foo where import Prelude x = () GHC must read Prelude.hi, but needs read nothing else to compile the module. Now suppose it's like this instead module Foo where import Prelude x = map module Prelude( map, filter ) where import GHC.Map( map ) import GHC.Filter( filter ) Now when compiling Foo, GHC reads Prelude.hi, and sees that GHC.Map.map is brought into scope. Since that function is *used* in Foo, GHC also reads GHC.Map.hi to find GHC.Map.map's type, unfolding, arity, strictness etc etc. But it doesn't read GHC.Filter. In the *presence* of orphan modules, perhaps somewhere in the transitive closure of modules imported by Prelude, GHC must read those interface files too. We store a list of all orphan modules transitively below Prelude inside Prelude.hi, precisely so GHC knows which ones to read. Does that help? (If so, and you find it helpful, would you like to add some advice or information to the GHC wiki? So that those not reading this thread right now might be illuminated later.) Simon

Simon Peyton-Jones wrote:
In the *absence* of orphan modules, GHC reads as few interface files as possible. It must read the interface of every *directly-imported* module. After that, it's by-need only. For example module Foo where import Prelude x = () GHC must read Prelude.hi, but needs read nothing else to compile the module.
Now suppose it's like this instead module Foo where import Prelude x = map
module Prelude( map, filter ) where import GHC.Map( map ) import GHC.Filter( filter )
Now when compiling Foo, GHC reads Prelude.hi, and sees that GHC.Map.map is brought into scope. Since that function is *used* in Foo, GHC also reads GHC.Map.hi to find GHC.Map.map's type, unfolding, arity, strictness etc etc. But it doesn't read GHC.Filter.
In the *presence* of orphan modules, perhaps somewhere in the transitive closure of modules imported by Prelude, GHC must read those interface files too. We store a list of all orphan modules transitively below Prelude inside Prelude.hi, precisely so GHC knows which ones to read.
Does that help? (If so, and you find it helpful, would you like to add some advice or information to the GHC wiki? So that those not reading this thread right now might be illuminated later.)
Thanks for this explanation. I'ld rather like if someone else took my ignorance as feedback for improving the documentation, though. From your description I would conclude that the overhead wrt. orphaned instances comes from "wrapper" modules that basically reexport other modules (including orphaned modules). Or am I mistaken here, because instances are always reexported? Is there a difference for the situation: 1. module A data T instance C T and 2. module A (module TA) import TA import IA module IA import TA instance C T module TA data T except reading 3 instead of 1 interface files, as happens if I would split up an other module? Maybe it is not worth discussing about an overhead (or a disadvantage of orphaned modules) at all, since it is obviously faster if I only import a data type from a library without certain instances when I don't need these instances. Cheers Christian

Simon Peyton-Jones wrote:
Now when compiling Foo, GHC reads Prelude.hi, and sees that GHC.Map.map is brought into scope. Since that function is *used* in Foo, GHC also reads GHC.Map.hi to find GHC.Map.map's type, unfolding, arity, strictness etc etc. But it doesn't read GHC.Filter.
In the *presence* of orphan modules, perhaps somewhere in the transitive closure of modules imported by Prelude, GHC must read those interface files too. We store a list of all orphan modules transitively below Prelude inside Prelude.hi, precisely so GHC knows which ones to read.
Perhaps Prelude.hi could, instead of storing a *list* of orphan modules, store all the orphan instances themselves? Obviously that would waste a bit more space (less now that instances don't contain big function bodies in the HEAD; more because RULES can be orphan too, and numerous). Would it be any faster loading or is it just a bad idea? :-) -Isaac

Isaac Dupree wrote:
Perhaps Prelude.hi could, instead of storing a *list* of orphan modules, store all the orphan instances themselves? Obviously that would waste a bit more space (less now that instances don't contain big function bodies in the HEAD; more because RULES can be orphan too, and numerous). Would it be any faster loading or is it just a bad idea? :-)
I don't see a performance issue, and if there is one a ticket should be created for it (since there a sometimes good reasons for orphaned modules -- and good reasons to avoid them, too!) Cheers Christian
participants (15)
-
Aaron Denney
-
Ashley Yakeley
-
Christian Maeder
-
Claus Reinke
-
Duncan Coutts
-
Henning Thielemann
-
Ian Lynagh
-
Isaac Dupree
-
Jonathan Cast
-
kahl@cas.mcmaster.ca
-
Malcolm Wallace
-
Ross Paterson
-
Simon Marlow
-
Simon Peyton-Jones
-
Yitzchak Gale