4 ms·
> aka the original OO. OO as taught today is nothing like how Alan Kay imagined OO [1]. Alan Kay originally imagined OO as biological cells only able to communi
by lomnakkus 10y ago
> aka the original OO. OO as taught today is nothing like how Alan Kay imagined OO [1]. Alan Kay originally imagined OO as biological cells only able to communicate via message-passing. That's the actor model more or less.
Async message-passing has a huge problem when it comes to practicality: In any resource-constrained system (i.e. no unbounded queues) messages can get lost. I don't know if you feel comfortable with method calls having a "best-effort" semantic (which is what happens in the actor model and biology[2]), but it makes me deeply uncomfortable as a foundational model. At the very least you need some way to do retries, but if even looping is a method call, then how do you ensure even the reliability of retries? You could do it to arbitrary precision, I think, given enough duplication + repetition of code[1], but I don't understand why we'd want to do something so messy at a language level when we already have hardware that's reliable to 99.999%+ levels already.
[1] This also assumes that the interpreter/compiler reading the code is 100% reliable... which it wouldn't be if everything is actor-based. You can see the problem.
EDIT: [2] This is a perhaps-interesting aside: In biology "best effort" is typically the best you can do, given the limitations of fluids/energy/etc. You send out enough molecules of the right type to hope that the intended recipient has a decent chance of detecting them. These things have been fine-tuned through a billion+ years of evolution, but in computer systems we typically don't have that kind of (even simulated) time to do "just enough".
- true_religion 10y agoLooking at the Erlang model, there's no view that code is reliable. In fact the prevalent view is that code is unreliable and you should structure things to recover from failure at all points of the architecture. Messages can go missing. Calls can time out. Processes can crash for reasons you will never know about, and your architecture should be resilient against that. Whilst this sounds extremely complex, in practice it boils down to letting everything low level fail, and having supervisors who can handle the failure. Resource issues are a problem everywhere. For example, you want to save a file. What happens if the file system crashes after it claims it has saved? What happens if its a network connected drive, and it times out? What happens if its a file on Amazon S3, and your network cable just got cut by a tractor? You're going to have to deal with this at a higher level than the line of code which tried to save the file.
- lomnakkus 10y ago> You're going to have to deal with this at a higher level than the line of code which tried to save the file. Exactly, but that's the point I'm trying to make, perhaps badly. My point is: Can a function call fail in Erlang, i.e. can it just "not return"? AFAIUI as long as you're inside a message handler, this cannot happen -- any function call will receive a return value. In other words: Function calls inside message handlers are synchronous. In the Actor model conceived by Hewitt, this is not the case. Now, this would be a huge problem for any foundational theory, but he seems to get around it by just assuming infinte resources (queues), so it all works out in theory.
- di4na 10y agonot exactly. Inside an Actor, the Actor model of Hewitt say nothing. You can do whatever you want to decide what you do with the next message.
- masklinn 10y ago> My point is: Can a function call fail in Erlang, i.e. can it just "not return"? Kinda? Function calls in Erlang are intra-process and synchronous, but the function could send and receive messages internally and never return because it never got a response and did not have a timeout setup. When you're talking about actual messages between processes though, they are asynchronous and they can get lost (if only because the process you're sending a message to is on an other physical machine).
- swhipple 10y agoI think there are two separate issues here: unbounded queues vs finite resources and also the overhead of asynchronous message passing (or "don't make every particle its own actor"). Regarding applying backpressure, you're correct that Erlang doesn't have a silver bullet. Process mailboxes are unbounded and can exhaust resources. Or you can implement a buffer and drop messages based on some strategy. As for making every 'operation' asynchronous, you could do it and not run into any additional unbounded queue or error handling problems, but it would add overhead without any advantage over concurrency via preemption.
- 10y ago
- Xixi 10y agoThat's more or less how erlang work: by async message-passing, and it's used to build extremely (99.9999999%) reliable softwares. A "best-effort" semantic is more than enough: when you really care if the message has been received (that is to say most of the time), you make a "synchronous" call, which is really just two async calls (one in each direction), with a timeout. Even if the message back is just an acknowledgement that the message was received. In Erlang/OTP it's wrapped in an actor behaviour called "gen_server", and the default timeout is 5000 milliseconds. If it timeouts an exception is raised, and a common strategy is to simply let the process crash, and restart to try again [0]. On the other hand it's not async call all the way down: it's only the calls between actors that are asynchronous: if you write a loop [1] within your actor then it's synchronous. To write asynchronous code you need to spawn new actors (which is trivial, and will always by default result in an exception being raised if something get lost or timeout after 5 seconds). Note that when you write Erlang code the granularity of an actor is absolutely not the same as when you write OOP code: you don't wrap every data structure in a process, rather processes tend to be about processing data, or abstracting an IO point (a file, a socket, etc.) since the semantic is perfect. [0] The implementation of all of this takes more or less 1 line of code, this is really the defaults. [1] you need to write it recursively in Erlang.
- lomnakkus 10y agoErlang != OOP as imagined by Kay... as I understand Kay's intent. Erlang == "independent reliable units of computing". (I think Erlang programmers call them "functions"? Or maybe "processes"? AFAIR only the "process" level is subject to message loss, yes?) I'm sure you're right about most of what you wrote, but that's not the point I was getting at. EDIT: Just to expound: In Kay's conception even e.g. "==" inside a function would be a method invocation and it would be asynchronous (presumably taking two continuations, one for "equal" and another for "not equal"). This absurdity is why I fundamentally disagree with the Actor model (as a model of computation), but also with extremism such as Kay's. EDIT: Btw, I call bullshit on the 99.9999999% reliable service unless you can come up with a reference. I know that Erlang/OPT is known for legendary relaibility, but I'm unsure on what that means: Does it mean "no interruption" on any given stream (e.g. phone call). Does it mean "no more than X connections fail"?