Superclass defaults

Jonas Almström Duregård jonas.duregard at chalmers.se
Mon Aug 29 18:23:16 CEST 2011


Hi,

First of all, I love the idea of default superclass instances!

About the opt-out feature, the problem with option 3 is only present
if the superclass instance is defined in another module (you won't see
unexpected behavior from your own instances). One solution is to use
option 3 if the offending is defined in the same module and
reject/warn only when there is a superclass instance in another
module.

This way users are not surprised when the compiler rejects a
Functor/Applicative pair because they need to explicitly tell it to
hide the intrinsic Functor, and the case that Functor and Applicative
instances are defined in separate modules must be relatively rare
(outside the Applicative library)?

We might even require the data type to be defined in the same module
(which i guess is easier to check and still very common) to silently
override a default? Documenting this feature might not be very pretty
i guess...


I think the most important thing is to enable users to write
compatible code, i.e. modules that works with the Applicative class
whether it defines a default Functor or not. I suppose if option 1 is
used, hiding should be allowed even for classes that would not have
been defined anyway (with a warning)?

If we allow the Multi-headed instance declarations described in the
suggestion then we can always write compatible code by merging
instances, since an instance for (Functor,Applicative) would always
hide the default Functor instance if there is one (right?).

Regards,
Jonas


On 28 August 2011 23:21, Bas van Dijk <v.dijk.bas at gmail.com> wrote:
> On 22 August 2011 10:10, Simon Peyton-Jones <simonpj at microsoft.com> wrote:
>> | > I don't completely understant how does it work. Does client need to enable
>> | > language extension to get default instances?
>> |
>> | I think that the extension would only be required to *define them*,
>> | not for them to be generated. The more conservative choice would
>> | indeed be to require the extension for both, though.
>>
>> Yes. I've clarified http://hackage.haskell.org/trac/ghc/wiki/DefaultSuperclassInstances to say this.
>>
>> | > Also proposal cannot fix Functor/Applicative/Monad problem without breaking
>> | > client code. It requires explicit opt-out but client may define Applicative
>> | > instance. And unless "hiding" is added it will result in compile error.
>> |
>> | I think the intention (at least as I understand it) is that a
>> | superclass default is only used to generate an instance if there is
>> | not already some suitable instance in scope, just like a default
>> | method is only used if there is not some explicit definition for the
>> | method in the instance.
>>
>> Actually that is not what Conor and I proposed.  See http://hackage.haskell.org/trac/ghc/wiki/DefaultSuperclassInstances.  Under "Variations" we discuss the "silent-opt-out" choice.  But it's bad enough knowing exactly what instances are in scope (given that they are not named), let alone having that control what further instances are or are not generated!  For superclass defaults there is no such ambiguity.
>>
>> Simon
>>
>>
>> _______________________________________________
>> Glasgow-haskell-users mailing list
>> Glasgow-haskell-users at haskell.org
>> http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
>>
>
> Won't option 1 "Reject this as a duplicate instance declaration, which
> indeed it is." conflict with design goal 1: "a class C can be
> re-factored into a class C with a superclass S, without disturbing any
> clients"?
>
> Take the transformers package for example. It defines lot's of
> instances of Functor and Applicative for its monad transformers.
> Doesn't transformers have to be changed if we go for option 1 (by
> either dropping the Functor and Applicative instances or listing
> hiding clauses in the Monad instances) thereby seriously conflicting
> with the design goal of not disturbing any clients.
>
> I expected the semantics to be like option 3: "Allow the explicit to
> supersede the intrinsic default silently". It has the advantage of:
>
> 1) Not disturbing any client code.
>
> 2) Giving the ability to define optimized implementations if you're
> not happy with the default ones (without using the hiding mechanism).
>
> 3) Feeling very much like the semantics of default methods thereby
> conforming to the rule of least surprise.
>
> The argument against option 3, which I quote:
>
> "Option 3 avoids that problem but risks perplexity: if I make use of
> some cool package which introduces some Foo :: * -> *, I might notice
> that Foo is a monad and add a Monad Foo instance in my own code,
> expecting the Applicative Foo instance to be generated in concert; to
> my horror, I find my code has subtle bugs because the package
> introduced a different, non-monadic, Applicative Foo instance which
> I'm accidentally using instead."
>
> talks about "subtle bugs". Could you give an example of such a bug?
>
> I would expect that the non-monadic Applicative Foo instance is always
>  somehow "compatible" with the monadic one. However I don't have a
> clear definition of "compatible" yet...
>
> Thanks,
>
> Bas
>
> _______________________________________________
> Glasgow-haskell-users mailing list
> Glasgow-haskell-users at haskell.org
> http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
>



More information about the Glasgow-haskell-users mailing list