Skip to content

Multi-method classes are inlined/specialized better than single-method classes for strict types

Instances of single-method class are optimized better than instances of multi-method classes. Attached is a small example,

class Square a where
  square  :: a -> a

and a simple data type

data Pair a = Pair !a !a

instance Num a => Square (Pair a) where
  square  (Pair a b) = Pair (a*a) (b*b)

and a specialized function

squarepd :: Pair Double -> Pair Double
squarepd = pair

Compiled as is, squarepd will turn into this

Test.squarepd :: Test.Pair GHC.Float.Double -> Test.Pair GHC.Float.Double
[GlobalId]
[Arity 1
 NoCafRefs
 Str: DmdType U(U(L)U(L))m]
Test.squarepd =
  \ (eta_sgh :: Test.Pair GHC.Float.Double) ->
    case eta_sgh of wild_B1 { Test.Pair a_a60 b_a61 ->
    case a_a60 of wild1_agE { GHC.Float.D# x_agG ->
    case b_a61 of wild2_Xh2 { GHC.Float.D# x1_Xh7 ->
    Test.Pair
      @ GHC.Float.Double
      (GHC.Float.D# (GHC.Prim.*## x_agG x_agG))
      (GHC.Float.D# (GHC.Prim.*## x1_Xh7 x1_Xh7))    
    }}}

Now if you add another method to class Square (anything at all), this happens

Test.squarepd :: Test.Pair GHC.Float.Double -> Test.Pair GHC.Float.Double
[GlobalId]
[Arity 1
 NoCafRefs
 Str: DmdType U(U(L)U(L))m]
Test.squarepd =
  __inline_me (\ (ds_dgv :: Test.Pair GHC.Float.Double) ->
                 case ds_dgv of wild_Xi { Test.Pair a_a5Y b_a5Z ->
                 Test.$WPair
                   @ GHC.Float.Double
                   (GHC.Float.timesDouble a_a5Y a_a5Y)
                   (GHC.Float.timesDouble b_a5Z b_a5Z)
                 })

Which also what you get when you remove the strictness annotations from 'Pair'.

Trac metadata
Trac field Value
Version 6.8.3
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture Unknown
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information