Seemingly unused qualified import affects method visibility
Here is a simple test case:
module MyLib where
class MyClass a where
myMethod :: a -> a
module MyModule where
import MyLib (MyClass)
--import qualified MyLib as L
data Foo = Foo
instance MyClass Foo where
-- error: ‘myMethod’ is not a (visible) method of class ‘MyClass’
myMethod Foo = Foo
Since I have only imported MyClass
and not its methods (that would be import MyLib (MyClass(..))
), the error is correct, myMethod
is not visible. But if I uncomment the import qualified MyLib as L
line, the error disappears even though I do not use L
anywhere. Writing L.myMethod Foo = Foo
is not even legal!
I filed this under "confusing error message", so let me show you the conditions under which the above behaviour was confusing. We were using classy-prelude instead of Prelude
, but we were not familiar with all the differences between the two preludes. We started with code like this, which did not compile:
{-# LANGUAGE NoImplicitPrelude #-}
module MyModule
import ClassyPrelude
data Foo a = Foo
instance Foldable Foo where
-- 'foldMap' is not a (visible) method of class 'Foldable'
foldMap = undefined
So we clarified that we meant Prelude.Foldable
, in case ClassyFoldable.Foldable
meant something different.
{-# LANGUAGE NoImplicitPrelude #-}
module MyModule
import ClassyPrelude
import qualified Prelude
data Foo a = Foo
instance Prelude.Foldable Foo where
foldMap = undefined
This compiled, so we first thought that Prelude.Foldable
and ClassyPrelude.Foldable
were two different type classes, but we later discovered that ClassyPrelude.Foldable
is a re-export of Prelude.Foldable
. So the following means the same thing and also compiles:
{-# LANGUAGE NoImplicitPrelude #-}
module MyModule
import ClassyPrelude
import qualified Prelude
data Foo a = Foo
instance ClassyPrelude.Foldable Foo where
foldMap = undefined
At this point, the qualified Prelude
import doesn't seem used anywhere, so we thought it was safe to remove it:
{-# LANGUAGE NoImplicitPrelude #-}
import ClassyPrelude
data Foo a = Foo
instance ClassyPrelude.Foldable Foo where
-- 'foldMap' is not a (visible) method of class 'Foldable'
foldMap = undefined
But ClassyPrelude.foldMap
is not the same as Prelude.foldMap
, so this did not compile and it wasn't clear why.
One way to make this less confusing would be to allow qualified method names; this way, we would have tried both Prelude.foldMap = undefined
and ClassyPrelude.foldMap = undefined
, and we would have discovered the source of the problem.
Trac metadata
Trac field | Value |
---|---|
Version | 8.2.2 |
Type | Bug |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Compiler |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |