No, it's not a silver bullet, but neither is it some misbegotten relic of an earlier era as you posit.
This is in fact how we're starting to program in the 21st century and all programming will be of that type in the 22nd century.
The last popular languages that support this paradigm (Go, Rust, Erlang, Elixir) are exploding in popularity and entering the mainstream.
Message passing does in fact magically solve the problem of data integrity in parallelism when the data is immutable. Languages like Rust and Pony are starting to solve the deadlock problem, and 'data corruption' has nothing to do with messages or lack of messages.
Also almost forgot. Look at the wealth of message queues that exist (RabbitMQ, ActiveMQ, SQS, Kafka, ... the list goes on).
Just because your compiler uses GOTO / messaging behind the scenes to implement function calls, it doesn't follow that GOTO / messaging is the right API level for designing applications. We know this since 1968.
Can you explain that since its contrary to my experience. PDO and normal Objective-C methods had a return and are not one way.
A. One way communication, aka events, goto. Very useful as an implementation concept, but generally a poor idea for structuring applications, as it makes local reasoning about code harder than necessary.
B. Polymorphism, aka closures. This is a very useful device for modularizing code, albeit, in practice, vastly overused. It also happens to trivially fall out from the concept of "first class function". To have first class functions, we need to be able to create them at any point in the program, thus we need some form of variable capture to allow value capture, which was named "closure", in the example below "function g closes over variable x". Furthermore, we need to be able to return the function value we just created and invoke it later, in the example below the invocation of q(4) actually invokes the closure of g over 3. Once we have first class functions, we can add any number of concrete syntactic sugar constructs [classes, vtables, etc, etc, etc].
def f(x) = {
def g(y) = {
x + y
}
g
}
val q = f(3)
q(4)
IMHO, the "misunderstanding of OOP" is strongly attributable to a propensity in OOP community for using ambiguous terminology to pretend it possesses some sort of silver bullet, instead of recognizing the rather elementary computation constructs obscured by said terminology. In some alternate universe, we'd use "events" and "closures", and there will be very little misunderstanding. "messaging" is a false friend between computer languages and real world experience.So, while indeed still messaging, I'm not sure about the similarity to message queues/brokers in modern enterprise, where, as the parent said "By their nature such messages are asynchronous and unidirectional".
Where did you see that? That's not what the kind of messages we talk about are (e.g. in Smalltalk).
Perhaps (as some other commenter said) you have modern message queues in mind?
Closest analogy is the message queue (e.g. ESB) like Active MQ or Rabbit MQ (and the whole JMS tech), in which you do actually send a message and infrastructure does actually figure out who will receive and process it.
http://stackoverflow.com/questions/9062475/what-is-the-diffe...
Replace SOAP with HTTP, since SOAP is just an ill-advised, unnecessary, redundant obfuscation layer on top of HTTP, and so contrast still applies.
Obviously, message passing is alive and well for network protocols.
Actually, for many if not most, programming today means using procedures and subroutines, organized through functional decomposition, just like was done in the 1950s and 60s. We haven't gotten that far have we.
OO is a different paradigm from organizing the concepts in a domain through functional decomposition, and understanding how it is different, is key to understanding OO and messaging.
Seriously because unless you can define it, and quantify it then it is just rhetoric.
I'll try.
By the end of the 1950's, modular programming based on procedures and subroutines had become problematic. It was hard to have large teams of programmers working on parts of the code at the same time, and it was hard to create large well-structured programs.
The answer in the 1960's was to break down a problem into pieces, then sub-components, then subroutines through functional decomposition. This better allowed large problems to be understood, and worked on by different teams at the same time. This approach is known as structured programming.
This approach has resulted in quality software over the years, but suffers from painful limitations. One of the big ones is that as one works on a problem and discovers its requirements, the decomposition used needs to be modified, often from the top down.
Object orientation (much as for the "data" movement) represented a different way to approach a problem. Let's break down a large problem or system into entirely independent concepts that know how to to do things themselves. Let's not orchestrate concepts (objects) centrally, but instead have them do things themselves together to solve a problem. This comes close to the way we think. We recognize and organize things in our minds around us as objects. We differentiate between them by their attributes, and we classify them. When we see a tree we recognize it as such, and differentiate it from other by its attributes and also by its place in the hierarchy of types of trees we know. Behavior on the other hand is only immediately important to us if it is causal - for example if it threatens us. That unknown thing moving fast towards you prompts changes in your body, but once you recognize the object is a beetle and not a spider, you change.
Hopefully that helps.
OOP lets chunks of functions share state and hide that state from the wider application. More importantly you could have multiple instances of that shard state without explicit management, saving a lot of complexity and effort.
But closures do. And thus, why closures are a poor man's objects, and objects are a poor man's closures. As an example, Java closures are really anonymous objects with the closed state as instance variables.
> More importantly you could have multiple instances of that shard state without explicit management, saving a lot of complexity and effort.
Technically that's what classes gives you, not objects. But agreed on the sentiment.
If one thinks of them as proxies to the closed-over objects, they are quite like "procedures". Another way to think about them is simply as objects with only a single method.
Also, they can still be "pure functions". Purity is a relation of side effects, not of mechanisms. (Even then, it's a somewhat loose definition -- is allocating memory a side effect?) If you don't allow closures to escape their declared scope, you can handle closed values as extra parameters. So closures don't mean you suddenly can't write pure functions, it means that some input to the function is pre-determined. In other words, closures have the same implications to purity as parameter binding -- absolutely none.
> Even then, it's a somewhat loose definition -- is allocating memory a side effect?
This is leading nowhere. Is loading a value into a register a side effect? If you care.
No, that's what objects give you. Classes are merely one means of creating objects (others exist), but the benefits come from the objects, not their means of construction.
> We're moving away from it. This is not how we program in the 21st century.
Maybe it should be? Languages like Erlang and — to a much lesser extent — Go use message-passing semantics in at least some places.
To paraphrase Chesterton, message-passing has not been tried and found wanting; it's been found unusual and not tried.
Sadly, how we program in the 21st century isn't much different to how we programmed in the early 20th century when computers were first invented (at least to a 1st order approach).
Where are the Maxwell equations of Computer Science?
http://queue.acm.org/detail.cfm?id=1039523
https://www.amazon.com/LISP-Programmers-Manual-Michael-Levin...
Every task queue, every AMQP/message system are message based systems.
Modern development is lousy with message based architectures. It's just at the system level and not natively supported paradigm in most languages.
Honest question, btw, I really don't know.
This is what Sandi Metz talks about when she speaks about message/responsibility centric design vs data-centric design in OOP. The conceptual difference is said to lead to different designs. You don't start out your design by thinking about what data you hold but you think about which responsibilities/roles you have and create objects around those by thinking how they might talk to each other to reach their goals. (I'm currently reading POODR by Sandi Metz, so this is still new to me, if I got anything wrong there then please feel free to correct me)
https://www.practicingruby.com/articles/responsibility-centr...
Also David West Presentation https://www.youtube.com/watch?v=RdE-d_EhzmA
But when it comes down to it what really is message passing? You have a reference to an object, a method name and a collection of parameters. When you dispatch the message you look for the method on the object and run the function passing in the parameters. Does it matter if you optimise the situation by placing the parameters on a stack and using a dictionary with a reference to the method? Or if you optimise by doing static analysis to look up the method and replace the dispatch with a direct call to the method? Or if you optimise further by inlining the code altogether?
The point is not how it is implemented but how the programmer thinks of it. Object Oriented programming is a thing humans do, not a thing computers do. Object Oriented Programming Languages have features that make it more convenient to do Object Oriented programming. Whether the code is OO or not is only up to the programmer, not the compiler/interpreter.
Having said all that, is Ruby my first choice for (what I understand to be) Alan Kay's model of OOP? No. But then I really don't know what my first choice would be. It is possible that the language hasn't been written yet ;-)
Whether that conforms to Kay's (or your) definition of "message passing" is left to the reader.
On the contrary. We use it more than ever -- only similarly to Greenspun's tenth rule -- in "ad-hoc" and crappier implementations.
What do you think REST microservices are beneath the surface for example? Or AJAX, WebWorkers, SOAP. Etc. The bad parts of messaging without the flexibility (or even the performance of Smalltalk of the 90s) (Incidentally, Erlang/Elixir gets this right, Akka, etc). Or, all the Rabbit, Duck, Donkey MQs, ZeroMQs, pub/sub, event emitters etc out there.
>This is not how we program in the 21st century
That's more of a problem of the 21st century that messages.
>Besides, this idea of message passing is really not that useful for modern programming anyway but a lot of people still have this weird idea that message passing magically solves the problem of data integrity in parallelism. It doesn't. It does nothing to solve it. You can still have deadlocks and you can still have data corruption.
Deadlocks are not related to data integrity, so they're another story. As for "data corruption", messages where values are copied (and thus immutable) are not really prone to it compared to "how we program in the 21st century".
I hope it doesn’t dominate as OOP did in the 90s, as many other models such as actor and dataflow still have a lot of room for research and improvement.
Ruby.
We're moving away from it. This is not how we program in the 21st century. The last popular language that supported this paradigm (Objective C) is being replaced and will probably be all but gone in just a few years as Swift (not message based) takes it place.
Besides, this idea of message passing is really not that useful for modern programming anyway but a lot of people still have this weird idea that message passing magically solves the problem of data integrity in parallelism. It doesn't. It does nothing to solve it. You can still have deadlocks and you can still have data corruption.
The only approach that has provably improved our problems in this area is immutability, but even that paradigm comes at a cost that sometimes doesn't make it worth the trouble