1. 5

  2. 2

    Perhaps this becomes slightly more obvious (or perhaps not) when you notice that

    class Class a where
        foo :: <type depending on a>
        bar :: <another type depending on a>

    is just another way of saying

    data ClassDict a = { foo :: <type depending on a>
                       , bar :: <another type depending on a>, ... }
    class Class a where
        classDict :: ClassDict a

    In other words its easy to map between the collection of class members and its dictionary type.and the typeclass instance is just a privileged choice of value of dictionary type. In fact I kind of wish class definitions were given like

    class Class a -> ClassDict a

    or something equally silly.

    1. 1

      You can already write the latter thing. Typeclasses are, most practically, a mechanism for doing this automatically/globally/efficiently.

    2. 1

      It’s more similar to javascript than java. What are drawbacks to this approach? What is memory overhead for each function in Bicycle record created with acmeToBicycle? And here “using concrete class instance instead of interface instance” looks like huge computation, in Java it “just works”.

      1. 1

        I’m interested in Haskell but very new to the language. Could someone explain how the design presented in this post would be preferable over something like this?

        {-# LANGUAGE RecordWildCards #-}
        data Bicycle = Bicycle
            { cadence :: Int
            , speed   :: Int
            , gear    :: Int
        } deriving (Show)
        newAcmeBicycle :: Bicycle
        newAcmeBicycle = Bicycle 0 0 1
        newFooBicycle :: Bicycle
        newFooBicycle = Bicycle 0 0 4
        printStates :: Bicycle -> IO ()
        printStates Bicycle{..} = putStrLn $
            unlines ["cadence: " ++ show cadence,
                     "speed: " ++ show speed,
                     "gear: " ++ show gear]
        changeGear:: Bicycle -> Int -> Bicycle
        changeGear b g = b {gear = g}

        I’m guessing that it has something to do with record immutability but is it preferable to actually mutate the record fields rather than returning a new record with the new field values?

        1. 4

          (I’m the author of the post) You’re exactly right, what you’ve written is much better for most cases. I just wanted a more direct comparison; I think changing too many things in the Haskell translation would have obscured the focus of what I wanted to contrast.

          1. 1

            You’re right if you’re using records to store data - it’s usually better to create a fresh new copy with updated field values. However, if you’re doing object-oriented programming (and no language ought to prevent you from doing that if you so wish), you typically want the state and future behavior of objects to change in response to messages. For this reason, objects are modeled in Haskell as records of methods whose fields are (functions returning) IO actions.

            1. 1

              Thank you for the explanation. That’s very helpful for my understanding.

              Would implementing a message passing design have any benefits over just using records to store the data and functions that operate on those records? It seems like the design presented backs them into a corner where they lose ‘object’ polymorphism and instead need to implement a conversion function for each type of bike, like acmeToBicycle.

              Would this be considered the idiomatic way of addressing designing this system or am I reading a little too much into a design that was merely meant to show parallels between two seemingly unrelated concepts?