What's so bad about OverlappingInstances?

后端 未结 1 1695
佛祖请我去吃肉
佛祖请我去吃肉 2021-02-05 10:34

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 thi

1条回答
  •  醉酒成梦
    2021-02-05 11:20

    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).

    Unfortunately, this is broken with OverlappingInstances. For example:

    Module A:

    {-# LANGUAGE FlexibleInstances, OverlappingInstances, MultiParamTypeClasses, FunctionalDependencies #-}
    
    module A (Test(..)) where
    
    class Test a b c | a b -> c where
       test :: a -> b -> c
    
    instance Test String a String where
        test str _ = str
    

    Module B:

    module B where
    import A (Test(test))
    
    someFunc :: String -> Int -> String
    someFunc = test
    
    shouldEqualHello = someFunc "hello" 4
    

    shouldEqualHello does equal "hello" in module B.

    Now add the following instance declaration in A:

    instance Test String Int String where
        test s i = concat $ replicate i s
    

    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.

    0 讨论(0)
提交回复
热议问题