|
|
|
|
|
by riwsky
4365 days ago
|
|
Haskell's generic programming constructs do not have zero runtime overhead (at least on GHC, the dominant compiler). Typeclass-overloaded functions take an extra argument at runtime, in which the class "methods" are looked up. In particular, the typeclass-based definition of add3 turns into this Core code, which has an extra "$dNum_az0" arg to carry Num methods: ghci>let add3 a b c = a + b + c
==================== Simplified expression ====================
GHC.Base.returnIO
(GHC.Types.:
((\ (@ a_ayZ)
($dNum_az0 :: GHC.Num.Num a_ayZ)
(a_ayG :: a_ayZ)
(b_ayH :: a_ayZ)
(c_ayI :: a_ayZ) ->
GHC.Num.+ $dNum_az0 (GHC.Num.+ $dNum_az0 a_ayG b_ayH) c_ayI)
`cast` ...)
(GHC.Types.[]))
Compare this to the Int-specialized add3, which does not have to be passed the extra $dNum_az0 argument: ghci>let add3 a b c = a + b + c; add3 :: Int -> Int -> Int -> Int
==================== Simplified expression ====================
GHC.Base.returnIO
(GHC.Types.:
((\ (a_azj :: GHC.Types.Int)
(b_azk :: GHC.Types.Int)
(c_azl :: GHC.Types.Int) ->
GHC.Num.+
GHC.Num.$fNumInt (GHC.Num.+ GHC.Num.$fNumInt a_azj b_azk) c_azl)
`cast` ...)
(GHC.Types.[]))
Now, am I saying the the typeclass method isn't fast, or that GHC can't then optimize that Num dictionary away via specialization or inlining? No, I am not saying that. But it certainly doesn't always do that, resulting in a performance hit at runtime. More info @ http://www.haskell.org/haskellwiki/Performance/Overloading |
|