Superclass defaults

Jonas Almström Duregård jonas.duregard at chalmers.se
Fri Sep 2 17:50:11 CEST 2011


> The question then comes down to whether that warning should ever be
> strengthened to an error.

Indeed.

> I agree that such a scenario is possible. The present situation gives
> no choice but to do things badly, but things often get done badly the
> first time around anyway. Perhaps I'm just grumpy, but I think we
> should aim to make bad practice erroneous where practicable. Once
> the mistake is no longer forced upon us, it becomes a mistake that
> deserves its penalty in labour. Silent pre-emption is bad practice and
> code which relies on it should be fixed: it's not good to misconstrue
> an instance declaration because you don't know which instance
> declarations are somewhere else. Nonmonotonic reasoning is always a
> bit scary.
>
> From a library design perspective, we should certainly try to get these
> hierarchical choices right when we add classes. I accept that it should
> be cheap to fix mistakes (especially when the mistake is lack of
> foresight. Sticking with the warning rather than the error reduces the
> price of this particular legacy fix at the cost of tolerating misleading
> code. I agree that the balance of this trade-off is with the warning,
> for the moment, but I expect it to shift over time towards the error.
> But if it's clear what the issue is, then we can at least keep it under
> review.

I agree. Making bad practice erroneous is good, but its not really the
bad practice that raises the error here. You have no serious problems
until you try to change your bad design to a good one. Like you say it
should be cheap to fix mistakes.

>> Will there be a solution to this dilemma that I have missed? Should
>> the client code be allowed opt-out from the superclass preemptively
>> before it is given a default? Won't that cause a similar perplexity?
>
> I don't know what you mean by this. Perhaps you could expand on it?

What I'm trying to ask is if you can write compatible code that will
work across gradual changes of the compiler and the libraries.

Suppose we have library with class C. In a newer version of the
library we add an intrinsic superclass S. Also suppose the compiler
implements option 1. Now the users of the library want to write code
that uses both C and S, and that's compatible with both the new and
the old library. From what I can tell there are three situations that
needs to be covered:

1) Old compiler - Old library
Here we need to specify both instances, and we cant hide the default S
instance because its not supported by the compiler. This also applies
for other situations where the client must use Haskell 2010 compatible
code.

2) New compiler - Old library
Here we also need to specify both instances.

3) New compiler - New library
We can either write both instances and hide the default or we can just
write an instance for C.

Clearly code that covers situation 1 will never be compatible with situation 3.

The question I was asking was if we are allowed to hide the default
instance of S in situation 2. In that case you can write compatible
code for situation 2 and 3. The possible confusion from this is that
you hide a default implementation thats not defined. Maybe it's not as
bad as overriding silently, but there is some room for error where you
think you have blocked a superclass instance but really you have just
blocked some completely unrelated class.

Of course we can get compatibility across all three using CPP but I
really wish we won't need that.

As time passes, situation 1 will become more rare, although situation
2 and 3 can reoccur endlessly as new libraries are designed and
redesigned.

Regards,
Jonas



More information about the Glasgow-haskell-users mailing list