Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

There's cargo culting on both sides of the question.

Because someone heard pg say he's not overly fond of overly OO code (which he has said in the arc design document), or some other well-known thought leader on programming (like Yegge), they then form a particular dislike of all OO code and even the idea of OO, itself. It's not rational or very fully formed for most of the folks who hate OO. Likewise, there are folks coming from (maybe?) a Java or C++ background, who feel that strict OO is the only sane way to approach designing a program.

I'm not going to try to give examples of good or bad code in either category...but, will point out that Haskell is not an OO language (in the Grady Booch sense of OO, though you can encapsulate methods in data because it has first class functions), but there's an awful lot of beautiful and correct Haskell code out there. Likewise many other functional, Lisp, and ML-derived languages. OO design can obscure meaning, but there's no reason to get reactionary about it. It's one useful tool; it certainly works great for UIs and some types of API.



I'd like to try pushing the Haskell-is-an-OO-language bit a little further. I think Haskell98 is lacking, but with existential types you can model process entities in a way that I think is often underappreciated. As an off-the-cuff example, consider a counter. A simple approximation might be to say that (Int, Int -> Int) models a counter because it models the state of one, but it also fixes the implementation and fails to encapsulate.

But we can do better with existential types

    data Counter = 
      forall x . Counter { _step  :: x -> x
                         , _view  :: x -> Int
                         , _state :: x
                         }

    step :: Counter -> Counter
    step c@(Counter {..}) = c { state = _step _state }

    view :: Counter -> Int
    view (Counter {..}) = _view _state
At this point, we're passing around the internal state as "some type x" which can never be inspected, achieving encapsulation. We can create general functions that manipulate Counters

    stepTwiceThenShowEm :: Counter -> Int
    stepTwicethenShowEm = view . step . step
and we can easily create alternative implementations

    intCounter, integerCounter, listCounter, unCounter :: Counter

    intCounter     = Counter succ  id        (0 :: Int)
    integerCounter = Counter succ  id        (0 :: Integer)
    listCounter    = Counter (():) length    []
    unCounter      = Counter id    (const 4) ()
We also now must start thinking of our "objects" as entities because we cannot compare their internal state for equality (unless we give it an Eq constraint). This begins to quickly demand we keep some notion of state as we need to model "pointer equality" pretty quickly.

We can even do HAS A subtyping. Lenses make this very powerful.

    data TwoCounters = 
      forall x . TwoCounters { _c1    :: Lens' x Counter
                             , _c2    :: Lens' x Counter
                             , _state :: x
                             }
There's no doubt that this is an uncommon technique in Haskell, but it's worth stating that there are a LOT of similarities between codata modeling like this and typeclasses.

Finally, I began to follow a lot of this due to a middling popular library `folds` [1] which describes very generic ways of traversing data structures and accumulating some kind of result state. Basically all of the types dealt with in this library (L1, L1', M1, R1, L, L', M, R) are existentially quantified codata "objects" like I described above. This makes for very general code.

[1] http://hackage.haskell.org/package/folds


By the way, for those who aren't familiar with Lenses, it's not a bad thing to think of them as getter/setter pairs (which should be a little unsurprising at this point). They're first class, more principled, and more generalizable than your typical getter/setter pair... but my use of them here is far from unintentional.


You're right, except that Java and C++ don't have much to do with strict OO.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: