Functional programming is not a paradigm

Michael "notriddle" Howell on January 31, 2019

Or; functional and object-oriented are members of two different classes. What is a programming paradigm? When somebody talks about a ... [Read Full]
markdown guide
 

You're creating a new definition of paradigm, one that doesn't help anything. Nobody doing OOP believes that everything needs to be OOP. A system will mix a variety of paradigms, trying to find a combination that works well.

You can write entire components in a functional manner, so I don't get how it isn't a structural system. Some components are perfectly structured are pure computations.

 

I second this.

I apologize if I sound harsh, but I do feel the need to correct what I believe to be a few mistakes. Specifically:

but there ain't no rule in functional programming that stops you from making this function, that operates on raw numbers, visible to the whole world. That's why it's not a paradigm.

This is not a valid conclusion. Nothing about being a paradigm requires hiding certain functions. FP has a strong mathematical basis, one that allows for unlimited composition, so it does not need this kind of distinction of complexity and meaning.

Since you are comparing a declarative paradigm exclusively to imperative ones, differences will show up.

Regardless of terminology, your conclusion also seems incorrect to me:

Effectively writing functional code, then, still requires you to make a plan for your software system's architecture beyond "functional design"

This is false if your architecture were truly functional. In that case you'd only need to decide which functions to expose. Getting to a functional architecture is a different matter. I, for one, have never seen one. For instance, using IO monads in Haskell to create a webserver is still a form of imperative programming.

A point I'd like to make about OOP:

I "mutate" the person by returning a new instance with the applied changes

This is not OOP. That requires mutable state, returning a different object is not the same.
In particular, in OOP, A and B may both have a reference to C, if A causes C to change, B will see those changes. In FP, B will not. This is why OOP fails to deliver on its promise of encapsulation whereas FP succeeds.

 

I definitely agree. I was having the same thought as I was reading through this.

Anyhow, as you know, functional programming is more than just "I wrote a lambda," the same as object-oriented programming is more than just "I created an object." You can use the tools of any paradigm, but the paradigm itself has more to do with structure than anything, and again, that structure can be a hybrid of any variety of paradigms. (For example, my personal favorite is OOP+Generic).

 

Interesting. When I think of the major paradigms of programming, the list that comes to mind is imperative, functional, logic, relational, and maybe concatenative. Each corresponds to a mathematical model of computation and contains a universe of practice derived from that model. So I think what you're really seeing is different communities of practice with somewhat different usages of the already vague term "paradigm."

Are you going to model your solution as message passing? Reaction to events? What, if anything, will you use to draw boundaries between parts of your system?

In functional or logic languages, you would usually end up treating it as tail call recursion. For example, the main loop of an HTTP server in Prolog does something like

accept_loop(Socket) :-
  tcp_accept(Socket, ClientSocket, PeerIP),
  thread_create(handle(ClientSocket), _),
  accept_loop(Socket).

In Scheme it would be something very similar

(define (accept-loop socket)
  (define client-socket (accept socket))
  (fork-thread (lambda () (handle client-socket))
  (accept-loop socket))

In Haskell and other lazy languages, the main structure is often a fold over an infinite sequence.

 

So I think what you're really seeing is different communities of practice with somewhat different usages of the already vague term "paradigm."

Probably, yeah. It conflates the tactical choice of avoiding mutability with strategic choices like SOLID or the Actor model.

In functional or logic languages, you would usually end up treating it as tail call recursion.

That's not wrong, but it's a low-level implementation detail, not an insight into how to structure your application overall. That recursion or sequence evaluation is usually hidden behind an abstraction like gen_tcp or the callback given to serve.

 

A programming paradigm is an approach to programming a computer based on a mathematical theory or a coherent set of principles. Each paradigm supports a set of concepts that makes it the best for a certain kind of problem. For example, object-oriented programming is best for problems with a large number of related data abstractions organized in a hierarchy. Logic programming is best for transforming or navigating complex symbolic structures according to logical rules. Discrete synchronous programming is best for reactive problems, i.e., problems that consist of reactions to sequences of external events. Languages that support these three paradigms are respectively Java, Prolog, and Esterel.

See full version here info.ucl.ac.be/~pvr/VanRoyChapter.pdf

 

You haven't written vtables by hand here. Furthermore there's no need for protocols or macros here. You've basically accomplished what's stated. Showing encapsulation (assuming you put this all in a module) of data and behavior without OOP. This is pretty much the same amount of code it would take to write this in a OOP style as well.

Unless you're subtyping, which is where vtables become required, classes vs structures and modules are more or less identical. Unless of course you're trying to encapsulate more than one data type together with a set of behavior, in which case most class systems are incapable whereas with modules it's trivial.

 

You're right; I forgot to account for subclassing.

If I switched off of pattern matching to pull out the closures and instead used Kernel.elem, it would work with tuples of varying length. Then you'd be able to write subclasses by replacing the closures with your own, and add additional items to the end to add more methods.

 
code of conduct - report abuse