Well put. The majority of language development for the last 20 years has proceeded by adding more features into languages, as they all borrow keywords and execution semantics from each other. It's like a neighborhood version of corporate bureaucracies, where each looks across the street, and decides "they've got a department we don't have, we better add one of those".
I like languages that dare to try to do more with less. Zig's comptime, especially the way it supplants generics, is pretty darn awesome.
I was having a similar feeling with Elixir the other day, when I realized that I could built every single standard IPC mechanism that you might find in something like python.threading (Queue, Mutex, RecursionLock, Condition, Barrier, etc) with the Erlang/Beam/Process mailbox.
Yeah, I have no idea what shevy-java is talking about either. I would accept “huge step too far”, but not backwards. Unless your belief is that on the 8th day God gave mankind Algol syntax and said “let all languages look like this”. I’ll give that it can feel pretty foreign, like forth, lisp, erlang also do. These languages, imo, all use syntax where the form of the syntax binds nicely, reinforces even, with their computation models.
For me, often, it’s an escape for a GUI world taken over by out-of-control “design” tenets. I value good Ux design concerns, but often working with designers lately feels bureaucratic, at times cargo culting, and overly spacious.
It’s like a graphical form of “I didn’t have time to give you a short answer, so I gave you a long one instead”. TUIs force a paucity that often makes for a nice information/pixels ratio.
I did Smalltalk for ~20 years as my primary. I’m a polyglot now, maintaining/implementing in C, Python, Swift, Kotlin, and Elixir.
The thing (for me) about Smalltalk was the thought to code ratio. It was awesome. It had a pretty good balance of less is more. Where working in Swift and Kotlin feel like trying to navigate the many nuances of American football or cricket, Smalltalk was like playing soccer/football-sans-america. The syntax is simple. And the computation model is straitforward and simple.
Elixir is kind of like that, computationally, a few simple concepts and everything builds on that. The saddest part about Elixir is that it ran with the whole do/end syntax. Drives me nuts. But I love that computationally, though different than Smalltalk, it’s like Smalltalk in that it’s a simple consistent model.
I do a lot of glueware and semi-embedded stuff with Python... but my goto these days for anything networky is Elixir (LiveView if ux). If I need an event loop, async that is more than a patched on keyword, it just rocks. It is amazing to me how much Elixir does not have, and yet how capably it solves so many problems that other languages have had to add support for to solve.
That was “quite a few” words. I wish the author had taken more time with Elixir/Erlang.
Languages like rust/python that use lots of reserved keywords, especially for control flow seem to have reached for that arrow to solve the “event loop” problem as described.
In BEAM languages, that very event loop stays front and center, you don’t have this awkward entanglement between reserved keywords and event loop. If you want another chunk of thing to happen later because of an event, you just arrange for an event of that nature to be delivered. No callbacks. No async coloring. Just events. The solution to the event problem is to double down and make your event loop more generally usable.
Interesting. Does that mean if you want to say, make an asynchronous http request, you do something like “fire_event(HttpRequestEvent(…))” which returns immediately, and somewhere else define a handler like “on_event(HttpResponseEvent, function (event) { … })” ? So you kind of have to manually break your function up into a state machine composed of event handlers? How do you associate a given HttpResponseEvent with a specific HttpRequestEvent?
So yes, your event loop processes the results of asynchronous work launched because of earlier events the same way.
Part of what makes this work, is the awesome function clause matching. Coordinating origin of async work and result of async work is really easy because you can match on any form of terms your heart desires, and everything is always immutable.
It is a callback of sorts. But most languages do callbacks with some sort of anonymous closure mechanism (or more primitively, pass function pointer/identifiers). What makes BEAM interesting is its prevalence of generalizing callbacks themselves as more events (messages).
You can also define a callback function in, e.g., JavaScript, and pass its name instead of an anonymous closure. Does "BEAM" do anything that JavaScript can't or doesn't?
There are a few very large features that BEAM offers that, as far as I can tell, no other industrial language/VM implements. In particular, BEAM is meant for distributed computation.
You can spawn new processes, communicate between processes (which don't have to be on the same computer), sending any kind of data between them including closures.
BEAM also has an error model designed to handle concurrent and distributed failures, e.g. a process may fail and another process (which, again, may or may not be on the same machine) monitoring it may decide to restart it, or to do some recovery, etc.
BEAM builds into it a number of the features for which we use orchestration, observability, just simpler and (generally) more flexible. And this is a platform that has been used in the industry since the 90s.
I deal with async function coloring in swift and Kotlin. Have avoided it (somehow) in our Python codebase. And in Elixir, I do things on separate processes all the time, but never feel like I’m wrestling with function coloring. I do like Zig (what little I’ve played with), but continue to wish that for concurrent style computation, people would just use BEAM based languages.
Hear hear. Elixir is a dream for this kind of stuff. But it requires very different decisions "all the way down" to make it work outside of BEAM. And BEAM itself feels heavy to most systems devs.
(IMO it's not for many use cases, and to the extent it is I'm happy to see things like AtomVM start to address it.)
As I was reading through the post, and the comments here, and pondering my own many hours with these tools, I was suddenly reminded of one of my favorite studio C sketches: An Unfortunate Fortune
What has changed is the “messaging” around the topic. This is very common with the Trump administration. When all is said and done, when exceptions are made/bought, and the courts and others get involved, it ends up not being much of a needle move. BUT, what is different every time is the messaging. And I have come to believe, that is what the actual goal is to some degree. The real goal is to send a message to people who are immigrants OR (and this is important) look like immigrants. It’s a message of “remember your place” and “be grateful you get to be here”. It’s the same type of tactics that gets sent to Asian communities, black communities, women, etc.
I am white. I am a male. I am 55. I oscillate between despondently sad and disgusted.
I like languages that dare to try to do more with less. Zig's comptime, especially the way it supplants generics, is pretty darn awesome.
I was having a similar feeling with Elixir the other day, when I realized that I could built every single standard IPC mechanism that you might find in something like python.threading (Queue, Mutex, RecursionLock, Condition, Barrier, etc) with the Erlang/Beam/Process mailbox.
reply