4 ms·
> you can't design real-world systems that way in OOP languages In most OOP languages. Out of many different languages which implement various interpretations
by klibertp 5y ago
> you can't design real-world systems that way in OOP languages
In most OOP languages. Out of many different languages which implement various interpretations of how OO should work, I found Io to be the purest, and for some odd reasons the most practical, implementation of object orientation.
In Io, you get two primitives: objects with slots and messages (which are also objects, of course). There's literally nothing else in the language. There's a bit of syntactic sugar, or rather, there can be a bit of syntactic sugar if you want, because the parser is an object you can customize on runtime, but otherwise it's just objects and messages. Message contents can be passed by name (lazily), and you can transform messages in any way you want before they get send. Or after. Taken together, you get a run-time equivalent of Lisp macros (Io is also homoiconic, btw). Add to it the fact you can reify interpreter state as first-class objects, and you get incredibly expressive language based on extremely small set of concepts. I think allowing messages to be first-class values able to exist without specyfing a target is the key here. It's also what Erlang does, with the difference being the sending and receiving messages in Erlang is hardcoded in BEAM, while it's 100% customizable in Io.
My favourite example of the power of Io:
someObj someMsg(some, args)
this is a simple message send. It will try to look up `someMsg` slot in the target `someObj`, will traverse the prototype chain if needed, and will activate the content of the slot if it's a block of code.
someObj @(someMsg(some, args)) # outer parens optional
this also a simple message send, where the message name is `@`. `@` is defined in `Object`, root of all prototype chains, and it: suspends evaluation of `someMsg`, saves a pair of `someObject`+`someMsg` in a queue in a Scheduler object and returns immediately. In other words, this time the message is delivered asynchronously, and executed the next time some Coroutine (including main) yields. It's not a built-in primitive, you can implement `@` yourself pretty easily.
...anyway, when I hear about message passing, and think about it being "done right" it's "Io and Erlang" that come to mind. Very different implementations, but they both work exceptionally well.