Introducing Instances in GHC point releases

So this is annoying (CCing -cafe) I need NominalDiffTime and UTCTime to have Typeable instances. In 6.10.1, they didn't ship with them out of the box, so I added them. Apparently, in 6.10.3, they DO ship with those instances out of the box. Annoyingly, that means that my code breaks on 6.10.3. Even more annoyingly, __GLASGOW_HASKELL__ is still 610, so I can't even work around this via cpphs. There appears to be no way to make code that requires those Typeable instances work with both 6.10.1 and 6.10.3. Yet another reason to avoid API incompatibilities in point releases. Does anybody have an idea on the best way to handle this? -- John Don Stewart wrote:
convertible appears broken with 6.10.3. Any thoughts?
Writing new package config file... done. Downloading convertible-1.0.1... Configuring convertible-1.0.1... Preprocessing library convertible-1.0.1... Preprocessing executables for convertible-1.0.1... Building convertible-1.0.1... [1 of 8] Compiling Data.Convertible.Base ( Data/Convertible/Base.hs, dist/build/Data/Convertible/Base.o ) [2 of 8] Compiling Data.Convertible.Utils ( Data/Convertible/Utils.hs, dist/build/Data/Convertible/Utils.o ) [3 of 8] Compiling Data.Convertible.Instances.Map ( Data/Convertible/Instances/Map.hs, dist/build/Data/Convertible/Instances/Map.o ) [4 of 8] Compiling Data.Convertible.Instances.Num ( Data/Convertible/Instances/Num.hs, dist/build/Data/Convertible/Instances/Num.o ) [5 of 8] Compiling Data.Convertible.Instances.C ( Data/Convertible/Instances/C.hs, dist/build/Data/Convertible/Instances/C.o ) [6 of 8] Compiling Data.Convertible.Instances.Time ( Data/Convertible/Instances/Time.hs, dist/build/Data/Convertible/Instances/Time.o )
Data/Convertible/Instances/Time.hs:61:9: Duplicate instance declarations: instance Typeable NominalDiffTime -- Defined at Data/Convertible/Instances/Time.hs:61:9-32 instance Typeable NominalDiffTime -- Defined in time-1.1.3:Data.Time.Clock.UTC
Data/Convertible/Instances/Time.hs:64:9: Duplicate instance declarations: instance Typeable UTCTime -- Defined at Data/Convertible/Instances/Time.hs:64:9-24 instance Typeable UTCTime -- Defined in time-1.1.3:Data.Time.Clock.UTC cabal: Error: some packages failed to install: HDBC-2.1.0 depends on convertible-1.0.1 which failed to install. convertible-1.0.1 failed during the building phase. The exception was:

Since those types come out of the time library, and that library's
version *has* been bumped (I assume), couldn't you use Cabal to
condition on the version of the time library to determine whether or
not to have CPP set a -DTYPEABLE_IN_TIME flag, and then #ifdef out
your versions of the instances?
I suppose a nice compiler extension would be "recessive instances"
which would take effect only if they did not overlap with another
instance. Probably a lot of corner cases involving multiple recessive
instances to work out, though.
Alex
On Thu, May 21, 2009 at 2:53 PM, John Goerzen
So this is annoying (CCing -cafe)
I need NominalDiffTime and UTCTime to have Typeable instances. In 6.10.1, they didn't ship with them out of the box, so I added them. Apparently, in 6.10.3, they DO ship with those instances out of the box.
Annoyingly, that means that my code breaks on 6.10.3.
Even more annoyingly, __GLASGOW_HASKELL__ is still 610, so I can't even work around this via cpphs. There appears to be no way to make code that requires those Typeable instances work with both 6.10.1 and 6.10.3.
Yet another reason to avoid API incompatibilities in point releases.
Does anybody have an idea on the best way to handle this?
-- John
Don Stewart wrote:
convertible appears broken with 6.10.3. Any thoughts?
Writing new package config file... done. Downloading convertible-1.0.1... Configuring convertible-1.0.1... Preprocessing library convertible-1.0.1... Preprocessing executables for convertible-1.0.1... Building convertible-1.0.1... [1 of 8] Compiling Data.Convertible.Base ( Data/Convertible/Base.hs, dist/build/Data/Convertible/Base.o ) [2 of 8] Compiling Data.Convertible.Utils ( Data/Convertible/Utils.hs, dist/build/Data/Convertible/Utils.o ) [3 of 8] Compiling Data.Convertible.Instances.Map ( Data/Convertible/Instances/Map.hs, dist/build/Data/Convertible/Instances/Map.o ) [4 of 8] Compiling Data.Convertible.Instances.Num ( Data/Convertible/Instances/Num.hs, dist/build/Data/Convertible/Instances/Num.o ) [5 of 8] Compiling Data.Convertible.Instances.C ( Data/Convertible/Instances/C.hs, dist/build/Data/Convertible/Instances/C.o ) [6 of 8] Compiling Data.Convertible.Instances.Time ( Data/Convertible/Instances/Time.hs, dist/build/Data/Convertible/Instances/Time.o )
Data/Convertible/Instances/Time.hs:61:9: Duplicate instance declarations: instance Typeable NominalDiffTime -- Defined at Data/Convertible/Instances/Time.hs:61:9-32 instance Typeable NominalDiffTime -- Defined in time-1.1.3:Data.Time.Clock.UTC
Data/Convertible/Instances/Time.hs:64:9: Duplicate instance declarations: instance Typeable UTCTime -- Defined at Data/Convertible/Instances/Time.hs:64:9-24 instance Typeable UTCTime -- Defined in time-1.1.3:Data.Time.Clock.UTC cabal: Error: some packages failed to install: HDBC-2.1.0 depends on convertible-1.0.1 which failed to install. convertible-1.0.1 failed during the building phase. The exception was:
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Thu, 2009-05-21 at 15:22 -0700, Alexander Dunlap wrote:
Since those types come out of the time library, and that library's version *has* been bumped (I assume), couldn't you use Cabal to condition on the version of the time library to determine whether or not to have CPP set a -DTYPEABLE_IN_TIME flag, and then #ifdef out your versions of the instances?
I was about to suggest this: #if MIN_VERSION_time(1,1,2) ... #endif because Cabal 1.6+ generates these cpp macros for you. Note that relying on the value of __GLASGOW_HASKELL__ would be wrong because the version of the time library is not directly related to the version of ghc. However, I note that all the recent versions of time are 1.1.2.x which means it didn't bump the API version when it added the instances. The PVP says: A.B is known as the major version number, and C the minor version number. When a package is updated, the following rules govern how the version number must change relative to the previous version: 1. If any entity was removed, or the types of any entities or the definitions of datatypes or classes were changed, or instances were added or removed, then the new A.B must be greater than the previous A.B. Duncan

Duncan Coutts wrote:
On Thu, 2009-05-21 at 15:22 -0700, Alexander Dunlap wrote:
Since those types come out of the time library, and that library's version *has* been bumped (I assume), couldn't you use Cabal to condition on the version of the time library to determine whether or not to have CPP set a -DTYPEABLE_IN_TIME flag, and then #ifdef out your versions of the instances?
I was about to suggest this:
#if MIN_VERSION_time(1,1,2) ... #endif
That would be slick. I'll give that a whirl. What version of Cabal does GHC 6.8 come from, and where can I read about the above feature? I imagine I may have to wrap the above in a __GLASGOW_HASKELL__ test for GHC 6.8 or something. Though if *cabal* and not GHC generates it, isn't that a bit hurting to my portability? (Can't just ghc --make with it, or ghci on it directly anymore, etc.) May be a needed tradeoff though.
because Cabal 1.6+ generates these cpp macros for you. Note that relying on the value of __GLASGOW_HASKELL__ would be wrong because the version of the time library is not directly related to the version of ghc.
Yeah, but when you've got nothing else to go on, it sometimes works in a pinch.
However, I note that all the recent versions of time are 1.1.2.x which means it didn't bump the API version when it added the instances.
Ashley, I'll forgive you this time ;-) I guess my larger point is just a plea to the community: please be really careful about what you do to GHC in point releases. This is not the first issue that has screwed me in the GHC 6.10.x point releases. GHC (and the community) used to be really good about this. Is there something causing a regression here, or is it my imagination?

I guess my larger point is just a plea to the community: please be really careful about what you do to GHC in point releases. This is not the first issue that has screwed me in the GHC 6.10.x point releases.
I hope that the Haskell Platform will solve a lot of these issues. Clear, planned releases. Careful attention to versioning. And GHC can stop shipping custom lib variants, and instead just take the latest platform bundle.

On Thu, 2009-05-21 at 21:30 -0500, John Goerzen wrote:
Duncan Coutts wrote:
On Thu, 2009-05-21 at 15:22 -0700, Alexander Dunlap wrote:
Since those types come out of the time library, and that library's version *has* been bumped (I assume), couldn't you use Cabal to condition on the version of the time library to determine whether or not to have CPP set a -DTYPEABLE_IN_TIME flag, and then #ifdef out your versions of the instances?
I was about to suggest this:
#if MIN_VERSION_time(1,1,2) ... #endif
That would be slick. I'll give that a whirl. What version of Cabal does GHC 6.8 come from,
1.2.x
and where can I read about the above feature?
The user guide, section "Creating a package", subsection "Conditional compilation": http://haskell.org/cabal/release/cabal-latest/doc/users-guide/authors.html#c...
I imagine I may have to wrap the above in a __GLASGOW_HASKELL__ test for GHC 6.8 or something.
Again, there's no direct relationship between the version of ghc and the version of Cabal (though there is some correlation).
Though if *cabal* and not GHC generates it, isn't that a bit hurting to my portability? (Can't just ghc --make with it, or ghci on it directly anymore, etc.)
True. People have been asking for a way to get cabal to invoke ghci with all the right flags, which is a reasonable idea.
because Cabal 1.6+ generates these cpp macros for you. Note that relying on the value of __GLASGOW_HASKELL__ would be wrong because the version of the time library is not directly related to the version of ghc.
Yeah, but when you've got nothing else to go on, it sometimes works in a pinch.
Aye, it's ok for the people you don't upgrade things separately, and those people are less likely to be able to work out how to fix things.
I guess my larger point is just a plea to the community: please be really careful about what you do to GHC in point releases. This is not the first issue that has screwed me in the GHC 6.10.x point releases.
GHC (and the community) used to be really good about this. Is there something causing a regression here, or is it my imagination?
Yes, we're loosening the connection between ghc and the non-core packages, so that package maintainers make releases rather than the ghc maintainers doing so. What we're currently missing is a PVP checker: a tool to compare APIs of package versions and check that it is following the PVP. Ideally, we will have packages opt-in to follow the PVP for those packages that do opt-in we have the PVP enforced on hackage using the checker tool. Since the HP is almost certainly going to require packages to follow the PVP then this should eliminate this class of mistakes. But it does need the tool, and nobody is working on that at the moment. Duncan

Duncan Coutts wrote:
What we're currently missing is a PVP checker: a tool to compare APIs of package versions and check that it is following the PVP. Ideally, we will have packages opt-in to follow the PVP for those packages that do opt-in we have the PVP enforced on hackage using the checker tool. Since the HP is almost certainly going to require packages to follow the PVP then this should eliminate this class of mistakes. But it does need the tool, and nobody is working on that at the moment.
Recently, I wanted to compare two branches of one of my libraries to see what API changes I had made. My low-tech solution was to do a two-line hack on haddock so that it sorts the modules before generating Hoogle documentation, and then to compare (with diff) the two hoogle documentation files between the branches. The Hoogle format just seems to be a list of definitions with types, classes and instances -- so it seems to fit the bill. I imagine it's not foolproof, but perhaps this could be a quick fix, at least as a heuristic for a package maintainer ("hoogle-diff suggests you may have altered something, please check before continuing to upload")? Thanks, Neil.

duncan.coutts:
What we're currently missing is a PVP checker: a tool to compare APIs of package versions and check that it is following the PVP. Ideally, we will have packages opt-in to follow the PVP for those packages that do opt-in we have the PVP enforced on hackage using the checker tool. Since the HP is almost certainly going to require packages to follow the PVP then this should eliminate this class of mistakes. But it does need the tool, and nobody is working on that at the moment.
If I recall correct, CosmicRay wrote just such a thing (or similar to it) a while ago. John? -- Don

Don Stewart wrote:
duncan.coutts:
What we're currently missing is a PVP checker: a tool to compare APIs of package versions and check that it is following the PVP. Ideally, we will have packages opt-in to follow the PVP for those packages that do opt-in we have the PVP enforced on hackage using the checker tool. Since the HP is almost certainly going to require packages to follow the PVP then this should eliminate this class of mistakes. But it does need the tool, and nobody is working on that at the moment.
If I recall correct, CosmicRay wrote just such a thing (or similar to it) a while ago.
John?
Nope, that wasn't me. Maybe the other John?
-- Don

Hi John, On Thu, May 21, 2009 at 09:30:24PM -0500, John Goerzen wrote:
I guess my larger point is just a plea to the community: please be really careful about what you do to GHC in point releases.
We are careful about what goes into the official GHC release. However, ever since GHC 6.6 (when extralibs were first separated out), we have not made any guarantees about whether point releases come with the same, or a compatible, version; we just take what's in the darcs repo at the time of the release. Anyway, this will be a non-issue in 6.12, when there are no extralibs, and the Haskell Platform takes over the role. Thanks Ian

Duncan Coutts
The PVP says:
1. If any entity was removed, or the types of any entities or the definitions of datatypes or classes were changed, or instances were added or removed, then the new A.B must be greater than the previous A.B.
..and this should be machine-checkable, no? Adding support for this to Hackage, so that conforming/non-conforming libraries could be highlighted might make a good Hac or (part of a) GSoC project. -k -- If I haven't seen further, it is by standing in the footprints of giants

On Sun, 2009-05-24 at 16:36 +0200, Ketil Malde wrote:
Duncan Coutts
writes: The PVP says:
1. If any entity was removed, or the types of any entities or the definitions of datatypes or classes were changed, or instances were added or removed, then the new A.B must be greater than the previous A.B.
..and this should be machine-checkable, no? Adding support for this to Hackage, so that conforming/non-conforming libraries could be highlighted might make a good Hac or (part of a) GSoC project.
Yes exactly. We proposed it for this summer's GSoC but it didn't quite make the final cut. http://hackage.haskell.org/trac/summer-of-code/ticket/1565 Duncan

On Sun, 24 May 2009, Ketil Malde wrote:
Duncan Coutts
writes: The PVP says:
1. If any entity was removed, or the types of any entities or the definitions of datatypes or classes were changed, or instances were added or removed, then the new A.B must be greater than the previous A.B.
When I read this point the first time, I was fine with this convention. But the more hassle I had with orphan instances I came to the conclusion that they are bad enough that they should be treated like unqualified anonymous imports. I mean, version policy warrants that I can import a module of any package version of type A.B.* when I use exclusively qualified imports or explicit unqualified imports. Instances are always imported whenever you touch a module, you cannot exclude them. Thus they behave like anonymous imports - you cannot control what exactly is imported. Version policy does not support anonymous unqualified imports because it does not make any warranties if you import this way. What about orphan instances? If a module misses an instance that belongs to one of its types or its classes then it may be added by any other module in any other package. If that is done then those orphan instances are likely to clash sooner or later. The version policy should warrant that within the A.B.* version range I'm safe to import a module the qualified or explicitly unqualified way. But since orphan instances can get in the way, we don't have this warranty! Say I import packages foo-1.2.3 and bar-4.5.6, where foo exports orphan instance C T and bar does not import such an instance. I see that it works and think this will continue to work as long as I restrict to foo >=1.2.3 && <1.3 and bar >= 4.5.6 && <4.6. Now, the new version bar-4.5.7 starts to import package hmpf-8.9.0, which provides another orphan instance C T. It is allowed to depend on new packages in such a version bump, right? Now, my package can no longer be compiled, because 'bar' re-exports the orphan instance from 'hmpf'. My proposal is thus: Discourage orphan instances! If you encounter that an instance is missing and it is a canonical one, it should be added to the package that defines the type or the class. If there are several choices for the implementation then the package where the instance would belong to should document that. Then programmers should find a consensus which of the choices they prefer. If you cannot wait for an official adaption of the required instance, then you must work with newtype wrappers. There are cases where you must define an orphan instance. Then this should instance should go into a new package by consensus between the maintainer of the class and the maintainer of the type. However, when orphan instances are banned, then it would also be no problem to add instances to their home modules within the A.B.* range. So I vote for allowing this, too.

On 27/05/2009 22:02, Henning Thielemann wrote:
My proposal is thus: Discourage orphan instances! If you encounter that an instance is missing and it is a canonical one, it should be added to the package that defines the type or the class. If there are several choices for the implementation then the package where the instance would belong to should document that. Then programmers should find a consensus which of the choices they prefer. If you cannot wait for an official adaption of the required instance, then you must work with newtype wrappers.
Quite. I argued the "no orphan instances in libraries" position on the libraries list last year, here's the start of the (longish) thread: http://www.haskell.org/pipermail/libraries/2008-September/010618.html We ought to have a "guidelines for API design" section of the wiki somewhere, so we could put this in it. Cheers, Simon

On Thu, 28 May 2009, Simon Marlow wrote:
Quite. I argued the "no orphan instances in libraries" position on the libraries list last year, here's the start of the (longish) thread:
http://www.haskell.org/pipermail/libraries/2008-September/010618.html
I remember. What I propose additionally is, that, when orphan instances are banned, we can allow addition of instances with the A.B.* version range just like this is allowed for all other language elements.
We ought to have a "guidelines for API design" section of the wiki somewhere, so we could put this in it.
That's currently spread across Category:Style.

John Goerzen schrieb:
So this is annoying (CCing -cafe)
I need NominalDiffTime and UTCTime to have Typeable instances. In 6.10.1, they didn't ship with them out of the box, so I added them. Apparently, in 6.10.3, they DO ship with those instances out of the box.
Annoyingly, that means that my code breaks on 6.10.3.
After having conflicting instances several times with some types in the past, I came to the conclusion that I should never define orphan instances. Can you restrict your package to 6.10.3 where an "official" instance is available? http://www.haskell.org/haskellwiki/Orphan_instance

Henning Thielemann wrote:
John Goerzen schrieb:
So this is annoying (CCing -cafe)
I need NominalDiffTime and UTCTime to have Typeable instances. In 6.10.1, they didn't ship with them out of the box, so I added them. Apparently, in 6.10.3, they DO ship with those instances out of the box.
Annoyingly, that means that my code breaks on 6.10.3.
After having conflicting instances several times with some types in the past, I came to the conclusion that I should never define orphan instances. Can you restrict your package to 6.10.3 where an "official" instance is available?
I didn't care about presenting the instance to people using my library, but the instance was necessary within the library itself, and led to the compilation error. -- John
participants (10)
-
Alexander Dunlap
-
Don Stewart
-
Duncan Coutts
-
Henning Thielemann
-
Henning Thielemann
-
Ian Lynagh
-
John Goerzen
-
Ketil Malde
-
Neil Brown
-
Simon Marlow