News for hackers. Stuff that matters.
Re:When FP? And When OOP? (2013) by chriswarbo on Monday January 28, 2019 @06:44AM (#19016709)
> Adding a third type of payment (Cash) is as simple as adding "| Cash" to the definition

This is the "expression problem" https://en.wikipedia.org/wiki/Expression_problem

In FP with ADTs, anyone can write new functions for a datatype. Yet, as you say, adding a new case requires modifying the definition and existing functions.

In OOP, anyone can add a new case, by defining a new subclass. Yet writing a new method for that class requires modifying the definition and existing subclasses.

One of these isn't always better than the other, so it's useful to have both.

> If you try to describe this properly in C# you'll be writing an abstract outer class and N concrete inner classes, plus boilerplate for comparisons and so on.

This overhead is due to emulating one approach using another. It would also take a bunch of boilerplate to implement subclassing with ADTs (e.g. a sum type to describe the methods, a smart constructor to implement the inheritance, etc.).

(Personally I prefer ADTs too, but they're not a magic bullet)

Re:When FP? And When OOP? (2013) by unhammer on Monday January 28, 2019 @09:07AM (#19017479)
OCaml has ADT's, but also polymorphic variants[0] which are open, and let you say "these alternatives or more", or "these alternatives or less": https://v1.realworldocaml.org/v1/en/html/variants.html#polym...

It's the main thing I've missed from OCaml when programming in Haskell (you can sort of do something like this with typeclasses, but I much prefer the OCaml solution).

Re:When FP? And When OOP? (2013) by dan-robertson on Monday January 28, 2019 @10:40AM (#19018254)
Ocaml also has open variants where one can add cases to an existing sum type (essentially this is like exceptions but less special) and it’s objects are like a dual of polymorphic variants where you get a record which you may add fields to. Neither of these features is as commonly used as polymorphic variants however.
Re:When FP? And When OOP? (2013) by pdpi on Monday January 28, 2019 @07:14AM (#19016875)
Haskell's typeclasses (or, equivalently, traits in Rust) help a lot with this problem, though. It's one of the biggest language features I wish I had access to in more languages.
Re:When FP? And When OOP? (2013) by chriswarbo on Monday January 28, 2019 @12:04PM (#19019055)
Haskell type classes are great for most situations, except when they fail it can be quite spectacular. I think the "magic" of type classes comes from two things:

- All instances are thrown into one global namespace, so we don't need to worry about where to find the right one.

- There can be at most one instance per type. Hence there's no ambiguity about which one to pick.

These make it easy for the machine to pick the correct instance automatically. Unfortunately, it also means that every time we import or upgrade a library, there's the chance that it will break things by exposing an instance that clashes with what we have.

The "backpack" stuff looks interesting in this regard, although it seems very over-engineered (mostly due to legacy concerns).

Re:When FP? And When OOP? (2013) by 0db532a0 on Monday January 28, 2019 @02:35PM (#19020343)
What is backpack stuff?
Re:When FP? And When OOP? (2013) by sideeffffect on Monday January 28, 2019 @07:39PM (#19022643)
Re:When FP? And When OOP? (2013) by 0db532a0 on Tuesday January 29, 2019 @12:33PM (#19028163)
Oh thank goodness. Finally.
Re:When FP? And When OOP? (2013) by thesz on Tuesday January 29, 2019 @09:13AM (#19026385)
You are talking about expression problem: https://en.wikipedia.org/wiki/Expression_problem

"Extend program with new data types and new functions"

It is quite well studied and solved in various languages. And, in my opinion, typical OO language solution does not come as especially succinct.

Re:When FP? And When OOP? (2013) by chriswarbo on Wednesday January 30, 2019 @12:55PM (#19037417)
> It is quite well studied and solved in various languages

I wouldn't say the expression problem is "solved"; various languages pick different tradeoffs, but the underlying problem is still there.

The best description I've seen of this is at https://www.tedinski.com/2018/02/27/the-expression-problem.h...

Re:When FP? And When OOP? (2013) by AnaniasAnanas on Monday January 28, 2019 @09:12AM (#19017512)
> Yet, as you say, adding a new case requires modifying the definition and existing functions.

The same is true in java if you use instanceof. The thing is, just like enums inductive data type definitions are not supposed to be extended by any module other than the one declaring them, and adding more should be considered an API change.

Re:When FP? And When OOP? (2013) by chriswarbo on Monday January 28, 2019 @11:53AM (#19018972)
> The same is true in java if you use instanceof.

Java isn't a particularly pure example of OOP: it has `if`/`for`/`while`/etc. from structured programming, non-OO "primitive types", non-polymorphic `+`/`-`/`*`/etc. and so on. `instanceof` is another example of a non-OOP feature (the OOP approach would be an `isFoo` method, where each class can decide what to return).

> inductive data type definitions are not supposed to be extended by any module other than the one declaring them, and adding more should be considered an API change.

Exactly. Yet in OOP, anyone can add new subclasses whenever they like, without ever telling the original author, and instances of those subclasses can co-exist alongside any other subclasses and will (in theory) work fine with all the existing code written for the superclasses.

What if I altered your sentence to say the following:

"Functions acting on a datatype are not supposed to be extended by any module other than the one declaring that type, and adding more should be considered an API change."

This would seem crazy if we applied it to an FP language; yet that's exactly the case in OOP, where a fixed set of methods are implemented inside each class.