Classes with exactly one method and no superclass (or one superclass and no method) are called "unary classes".  And yes, they are still implemented with no overhead.

See this long Note:
https://gitlab.haskell.org/ghc/ghc/-/blame/master/compiler/GHC/Core/TyCon.hs#L1453

I find type classes very difficult to
evolve in a way that satisfies my stability needs. Part of the reason
for this is that type classes as typically used don't really permit
any form of data abstraction: you list out all the methods explicitly
in the class definition.  There is no data hiding. 

That's odd.   Can't you say
```
module M( C, warble ) where
   class C a where { op1, op2 :: a -> a }

warble :: C a => a -> a
warble = ...
```
and now a client of `M` can see `C` and `warble` but has no idea of the methods.

Of course if a client wants to make a new data type T into an instance of C then they need to know the methods, but that's reasonable: to make T an instance of C we must provide a witness for `op1` and `op2`.  So your teaser is indeed teasing.

Simon

On Wed, 10 Dec 2025 at 20:59, Tom Ellis <tom-lists-haskell-cafe-2023@jaguarpaw.co.uk> wrote:
Dear GHC friends,

I would like to know whether the representation of FooD1:

    data Foo = MkFoo A B

    class FooD1 where
      foo :: Foo

has a representation at least as efficient as FooD2:

    class FooD2 where
      fooA :: A
      fooB :: B

in particular, that FooD1 doesn't occur an extra indirection.  Now,
according to

    https://gitlab.haskell.org/ghc/ghc/-/issues/20897

FooD1 used to be compiled as a newtype, so the answer was "yes".  Then
something called "Plan B" (described in that ticket) was enacted, and
I believe the answer is therefore still "yes".

Can someone please confirm that?

For a teaser of why I want this: I find type classes very difficult to
evolve in a way that satisfies my stability needs. Part of the reason
for this is that type classes as typically used don't really permit
any form of data abstraction: you list out all the methods explicitly
in the class definition.  There is no data hiding.  To address this
issue I am considering defining classes abstractly, like

    class MyClass where
      myClassImpl :: MyClassD

for some abstract type MyClassD (i.e. whose implementation details are
not exposed to users) and I want to know if there would be a
performance cost.

Thanks,

Tom
_______________________________________________
ghc-devs mailing list -- ghc-devs@haskell.org
To unsubscribe send an email to ghc-devs-leave@haskell.org