Personally, I think forcing yourself to a specific paradigm is a waste of energy. I've tend to just write code that best expresses my intention. Sometimes the code turns out more oop, sometimes it turns out more fp, and often it's more of a mix.
Personally, I think forcing yourself to a specific paradigm is a waste of energy. I've tend to just write code that best expresses my intention. Sometimes the code turns out more oop, sometimes it turns out more fp, and often it's more of a mix.
I think it's misleading to think of FP as being necessarily opposed to OOP. While FP is very much in opposition to the stroustropian style of OOP in syntax and execution (which is what people mean these days), if you're going back to smalltalk-type message passing objects, arguably some FPs have the hands down best implementations of OOP.
Python:
class MyClass:
def __init__(self):
self.name = ""
def setname(self, new_name):
self.name = new_name
def getname(self):
return self.name
Usage: obj = MyClass()
obj.setname("joe")
obj.getname() #==> "joe"
Elixir: defmodule MyAgent do
def init(), do:
Agent.start_link(fn -> "" end)
def setname(obj, new_name), do:
Agent.update(obj, fn _ -> new_name end)
def getname(obj), do:
Agent.get(obj, &(&1))
end
usage: {:ok, obj} = MyAgent.init()
MyAgent.setname(obj, "joe")
MyAgent.getname(obj) #==> "joe"
Honestly, superficially, the difference is minor (obviously, under the hood they're way different; ironically I think the Elixir form is far more "explicit" than the python form)While you can write either flavor in most languages (even Elixir if you abuse ETS), concurrency's requirements for immutability and run-time support start becoming distinguishing factors.
someBool ifTrue: [ "some block to execute" ].
In that context, either the "True" object receives the message and executes the block, or the "False" object receives the message and doesn't execute it. (Or even some user defined object that just happens to have an ifTrue: message handler). (Sorry I might be a little off on the syntax and exact details, my Smalltalk is rusty)Loops and such are also similar. Granted most of these things probably end up being implemented in native code on a practical level for performance, but conceptually it's a very small language. Most of the standard library and IDE is written in itself. Ruby definitely has a lot of flexibility, but it also has way more built-ins and much more separation between "interpreter code" and "user code"
I think this is what people are missing when they bring up the point that messages and method calls seem very similar. In a practical sense yes, but the smalltalk style message system is more about messages being a fundamental building block of the entire system.
While “if” doesn't work that way in Ruby, loops do (there is a for..in statement, but it's syntax sugar for a call to #each, and not idiomatic to use it anyway.) Python does a lot of that; putting loosely C-style syntax as sugar around method calls (which themselves support more general message passing patterns than Java-style method calls.)
Synchronous method calling as limited message passing; synchronous method calling as general message passing, and asynchronous message passing.
Java and C++ and most static class-oriented OO languages are in th first group.
Ruby and Smalltalk (and JS, which isn't, barring more recent developments, class oriented OO, bit is still OO) and some other dynamic OO languages are in the second group.
Elixir/Erlang are in the third group.
Message passing is inherently an imperative idiom (whether synchronous or not), even though it may show up in languages that are largely declarative rather than imperative outside of message handling.
Not really, “a limited echo of message passing” would have probably been more accurate than limited message passing: C++ and Java Ivor a form of OO inspired by Smalltalk-style message passing but are implemented in a way which provides something much more limited.