RFC: Can DefaultSignature compile-time conditional APIs be regarded "benign"?
Herbert Valerio Riedel
hvr at gnu.org
Sun Nov 11 15:34:55 CET 2012
After recent discussions, from which I gathered that
(compile-time) conditional APIs should be avoided, I'm left wondering if
a certain kind of compile-time conditional API falls into that category
as well, or whether it can be classified as "benign" and should
therefore be tolerated.
So I'm posting this for open discussion in the hope to reach a community
consensus on whether the conditional use of the "DefaultSignature"
language extension in APIs should be tolerated or not (e.g. for
haskell-platform packages). To this end, in the rest of this post I try
to make a case for why this class of conditional APIs is harmless.
So what's bad about "conditional" APIs? The way I understand the issue
with respect to compile-time conditional APIs which either
a) omit exposed modules or exported symbols altogether based on
compile-time configuration, or even worse
b) export different type-signatures for the very same symbol based on
are "bad", as they cause problems in client code using those APIs, such
a) not being able to properly declare the dependency on specific API
features being enabled in the library API in CABAL files (since
CABAL only allows to depend package version numbers),
b) and from the other direction, there's no simple way for the library
package to advertise the conditional features currently present in
the registered package.
c) Moreover, if the client code wants to use symbols which depend on
compile-time configuration, it either becomes non-portable and/or
becomes compile-time conditional itself.
Note: It should be stressed that in the latter case the client code
needs to take care to *exactly* replicate the semantics of the
conditional switching between the API variants as employed by the
library code (which can be CPP-based and/or CABAL-based), as any
mismatch may result in compile time failures. This also poses the
issue on how to properly document this "meta-property" in the
library API documentation.
(there may be more reasons, I just listed the ones off the top of my head)
On the other hand, I think that there are cases, when a compile-time
conditional API is "benign", for instance when the following condition
a) the library package exposes a /non-essential/ API feature based only
on availability of a given compiler-feature/extension,
b) the conditional feature is only ever visible to the client code if
the client makes use of this compiler-feature itself, and last but
c) the semantics of the client code must not change if the client code
has been made portable (with respect to the availability of the
E.g. consider the following hypothetical class definition:
class Size a where
size :: a -> Int
default size :: Generic a => a -> Int
size x = ...Generics based implementation...
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
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)
Consequently, as both scenarios don't lead to problematic situations,
I'd argue that there is no harm in allowing this kind of compile-time
conditional APIs using the DefaultSignature language extension.
: "Proposal: Adding generics-based rnf-helper to `deepseq`"
on libraries list
: "[ANNOUNCE] hashable-generics"
on haskell-cafe list
More information about the Libraries