Wednesday, May 15, 2024

OOP for FP programmers, part 1

The following content is egregiously oversimplified.

I learned to program in Python, where classes are a sign of overthinking, and then worked using F#. Now I need to learn object-oriented programming for working in C#. This is difficult because:

  1. No one ever explains object-orientation to be understood by functional programmers.
  2. Many OOP and FP constructs are semantically quite similar, yet not quite identical.
  3. No one ever compares OOP and FP constructs; at best, they ask whether we should use object-oriented or functional programming, a highly questionable question.

Here is what I have so far:

Polymorphism is accomplished using discriminated unions, inheritance, and runtime type checks. Runtime type checks are a Wrong Thing because they do not give you exhaustive matching, whereas either other style requires you to say somewhere that you are purposely choosing not to implement logic. Discriminated unions require definition of all subtypes in one place but allow adding arbitrary use cases elsewhere. Inheritance requires definition of all use cases in one place but allows adding arbitrary subtypes later. Discriminated unions can be faked using Church encoding or the Visitor pattern. So you should use inheritance if you want to see all defined behaviors in one place, but discriminated unions if you want to see all defined subtypes in one place.

Inheritance works only on the instance level. Static inheritance is probably theoretically possible but would be a Wrong Thing for reasons I do not yet understand. The proper OOP solution is to model all polymorphic behaviors themselves single-method classes with no state, at which point the Jack Diederich in my head tells me to convert them to functions and just pass in a function parameter. I have not tried enough times to know yet why he is wrong.

Classes hold encapsulated state. They also hold the behaviors that may operate on that state. They also hold polymorphic behaviors, with or without state. They are also a means of organizing static methods. Each class should have its own file all to itself to reflect the class's status as the basic unit of programming. You cannot program in OOP effectively unless you dream at night of the soft embrace of the class.

Interfaces are objects of functions, sometimes with field references. They serve the same role as function parameters except without duck typing. Interfaces are different from function (and ref) parameters in that they can hold multiple functions, so we should probably use function parameters at first and then extract multiple function parameters into interfaces. Except that the Interface Segregation Principle might imply that at least most interfaces should have a single method?

This all seems highly complicated. I don't know why anyone goes to the trouble to learn OOP instead of matching on DUs and passing functions around. But if there is a reason, I want to find out.

No comments:

Post a Comment

Stuff I don't understand about C#

Rant ahead. Criticisms of the language and the language idioms are interspersed. Disclaimer: I've been wrong about C# before. My lack of...