
On Sun, 11 Nov 2012, Herbert Valerio Riedel wrote:
E.g. consider the following hypothetical class definition:
class Size a where size :: a -> Int #ifdef HAS_DEFAULT_SIGNATURE default size :: Generic a => a -> Int size x = ...Generics based implementation... #endif
Now, if the client code doesn't exploit the default-signature implementation, then the client code is perfectly portable, and even if the conditional API features are available they have no visible effect whatsoever.
OTOH, if the client code wants to make use of the default implementation, it needs to be built with a compiler supporting the Generics language feature, and due to a) the library is guaranteed to provide the default-signature implementation as well as soon as the client is able to use it. The client-code is now deliberately non-portable (but on the other hand, the operational semantics are guaranteed to be consistent, as there's only one case to consider)
That is, if I want to write a package that is portable I have to implement 'size' myself. But if I forget to do so then GHC will not warn me. That is, I have to know and remember that 'size' is somehow special. APIs that change according to available compiler features are more problematic than they look first. E.g. QuickCheck depends on TemplateHaskell if you run on GHC. That is, if you run on GHC then a module is included that provides TemplateHaskell functions. If you do not run on GHC this module is not included because you cannot use it anyway. However, this way QuickCheck becomes restricted to certain _versions_ of GHC, because TemplateHaskell changes from version to version of GHC. Thus when speaking about portability, we should always think about portability between GHC versions. (My proposal for a quote of the week is: GHC's strongest competitor is the next version of GHC.) Will the Generics based default implementation of 'size' be portable to future version of Generics? For a central package like deepseq I would prefer to provide functions like genericSize that other libraries can use if they want to rely on Generics. They would then write instance Size Foo where size = genericSize instead of instance Size Foo where This would be ok, wouldn't it?