Hacker News new | ask | show | jobs
by sooheon 3462 days ago
If you want to create a bar food (Finger Food object, not Cocktail), which also could use a garnish() method, which inherits from which? Or should both objects have a father, Garnishable object to inherit from? It's clear to me that object composition is less flexible than functional composition.
3 comments

You can have trait/interface. But since garnish will be doing different thing it is OK to have two implementation. FP looks nice in theoretical examples in real world not so much.

In FP you will end with garnishFingerFood and garnishCocktail because you need to encode somewhere a specifics of garnish action. In OOP you will have garnish methods on Coctail and FingerFood and specifics and related knowledge how you need to perform garnish will be on object itself.

OOP is really powerful concept but failing in languages that have shit implementation. Java, C++ forsake OOP principles for "performance" or are made by people that do not understand concepts (Python, PHP).

From the specific example you're presenting, I don't see how you couldn't just have a Garnishable typeclass, that implements garnish differently for the FingerFood or Cocktail types.

The comment that FP isn't nice in the real world is pure baloney. For lots of "real world" IO-bound types of problems there is nothing better suited than a functional programming language with powerful abstractions. Things like monads let you write code in an imperative style without losing any of the benefits of writing in the functional paradigm.

OOP doesn't actually have the market cornered on polymorphism. As my sibling replies show, FP languages have long known how to achieve it.
> In FP you will end with garnishFingerFood and garnishCocktail because you need to encode somewhere a specifics of garnish action. In OOP you will have garnish methods on Coctail and FingerFood and specifics and related knowledge how you need to perform garnish will be on object itself.

You're complecting. In the real world of Clojure, you could simply define a protocol and provide different implementations of "garnish".

You just have the method as an aspect that you import into the class ;)
Generic functions: functional yet dynamically dispatched.
Generics aren't dynamically dispatched. Java has type erasure and C# emits variants for every instance.
No, I was talking about (Common) Lisp's generic functions (http://clhs.lisp.se/Body/m_defgen.htm). I realize I did not give enough context. Define a generic function:

    (defgeneric garnish (what with-what))
Specialize it on one or multiple arguments:

    (defmethod garnish ((c cocktail) (f fruit)) ...)
    (defmethod garnish ((s sandwich) (h ham)) ...)
    ...
But you can use it like a function:

    (let ((currified (rcurry #'garnish :curry)))
      (map 'list currified items))
Ah my bad! :)

These look very much like Clojure's protocols and multi-methods.

Yes, more like multi-methods, except for standard qualifiers (:around, :before, ...) and user-defined ones. OTOH, Clojure allows you to define a custom dispatch function.
Ah yes, Clojure has no first-class support for aspects. Its easy enough to monkey patch definitions for the rare case when its needed.

Most of the time however I try to avoid aspects as they introduce hidden behaviour in existing functions, which can be hard to reason about at scale, especially with more than a few developers.