Pivoting off some recent questions, I figured I'd turn the spotlight on the old bogeyman, OverlappingInstances.

A few years ago I might've been asking this question in earnest: after all, you can provide useful default instances and others can override them with more specific ones when they need to, what can be so bad about that?

Along the way I've absorbed some apprecation for the viewpoint that OverlappingInstances is really not so clean, and best avoided; mainly stemming from the fact that it's not very well-grounded theoretically, unlike other big extensions.

But thinking about it, I'm not sure if I could explain what's really so bad about it to another person, if I were asked.

What I'm looking for is specific examples of ways in which using OverlappingInstances can lead to bad things happening, whether it's by subverting the type system or other invariants, or just general unexpectedness or messiness.

One particular problem I know of is that it breaks the property that merely adding or removing a single module import can't change the meaning of your program, because with the extension on, a new instance overlap could be silently added or removed. While I can see why that's unpleasant, I don't see why it's earth-shatteringly awful.

Bonus question: As long as we're on the subject of useful but not theoretically well-grounded extensions that can lead to bad happenings, how come GeneralizedNewtypeDeriving doesn't get the same bad rap? Is it because the negative possibilities are more easy to localize; that it's easier to see what would cause problems and say, "don't do that"?

(Note: I would prefer if the brunt of the answer focuses on OverlappingInstances, not IncoherentInstances which needs less explanation.)

The badness about GeneralizedNewtypeDeriving is an implementation bug. There's nothing bad about this extension as such, but ghc allows it in cases where it should be banned.
–
augustssJun 8 '12 at 2:45

@augustss, is it that simple? See hackage.haskell.org/trac/ghc/ticket/5498. Simon says he doesn't know of a simple syntactic test to determine when it should be banned, and that it requires new theoretical work and advancements in the type checker to make it safe.
–
glaebhoerlJun 8 '12 at 14:28

2

@illissius I didn't say it was an easy bug to fix, but still just an implementation bug. If GeneralizedNewtypeDeriving constructed real instances instead of playing tricks with type coercions this bug would not occur (which is how I implemented it 10 years ago in Bluespec).
–
augustssJun 9 '12 at 5:09

Ah, I see. I think that's exactly the part of it I was thinking of as not well grounded. Different perspectives.
–
glaebhoerlJun 9 '12 at 10:01

1 Answer
1

One principle that the haskell language attempts to abide by is adding extra methods/classes or instances in a given module should not cause any other modules that depend on the given module to either fail to compile or have different behaviour (as long as the dependent modules use explicit import lists).

It would be preferable if this didn't affect module B. It worked before this addition, and should work afterwards. Unfortunately, this isn't the case.

Module B still compiles, but now shouldEqualHello now equals "hellohellohellohello". The behaviour has changed even though no method it was originally using had changed.

What is worse is there is no way to go back to the old behaviour, as you cannot choose to not import an instance from a module. As you can imagine, this is very bad for backwards compatibility, as you cannot safely add new instances to a class that uses overlappinginstances, as it could change the behaviour of code that uses the module (especially true if you are writing library code). This is worse than a compile error, as it could be very difficult to track down the change.

The only safe time to use overlapping instances in my opinion is when you are writing a class that you know will never need additional instances. This may occur if you are doing some tricky type based code.

I see. That's basically the issue I acknowledged in the question, but you've done a good job of explaining why it's bad. Is this the only real problem with it?
–
glaebhoerlJun 8 '12 at 14:07

4

Yes, the 'only' real problem is that you can completely lose confluence and the ability to reason about your code. It kind of works if you are careful to define all instances that overlap in one module, but there are ways to abuse constraint kinds to do bad things where you pass the more specific case the less specific instance.
–
Edward KMETTJun 12 '12 at 0:07

1

@EdwardKmett What sense are you using the word "confluence" in here? The same one as for term rewriting systems?
–
glaebhoerlFeb 10 '14 at 7:54