I mean, unlike in typical hard FP languages like Haskell or Elm, mutable state is rampant in your average Elixir app, it's just spread out across many (global singleton) little processes. Only inside a process you're doing "true" FP but given how small the average process is in scope, in practice the only real big difference is that you can't to an `i++` style for loop. Oh no!
But once you leave the process boundary, and often even before it, all bets are off. The amount of Elixir forum messages I've read that go "you can't do X at that point, because Y hasn't completed yet" is nuts.
Eg you can't broadcast in a phoenix channel `join` because the channel hasn't been fully initialized yet. So you send yourself an :after_join message and do the broadcast in there. I don't know about you but to me this feels a lot more like C++ than like Haskell.
Or consider the library module Agent which is exactly identical in semantics to a global singleton variable in an OO/imperative language. It's just a blob of data that you can get or set.
Now, I don't think any of these are disadvantages. I did mostly C# and JavaScript before Elixir, so I'm used to the occasional mutable state flying around.
But I'll never understand that people like Elixir for being FP. You just get such a small subset of the usual advantages of FP that it feels like an implementation detail. There's lots of advantages, but freedom from thinking about state isn't one of them.
To be clear, the Elm model of putting everything into a big tree and and transforming that at every user input is very unusual among even FP languages, and is not the model typically used in Haskell. This might be what you are thinking of.
Edit: I also want to point out that Elixir processes can be registered globally to act as singletons, but by default you can spawn any number of agents or other processes at runtime, meaning they are not singletons.
On Haskell, yes, you can just work off a thread and write shared buffers. But you are better off using STM or Async (these are a bit like futures), which compose, and you can write pipelines out of them.
Not sure what you mean by "actor frameworks don't compose"?
Maybe composition for compositions' sake isn't that important?
Definitely. I was about to ask "but when did you actually need to compose actors and how does that even make sense?" -- and while I am sure there are people who would find a scenario I feel that would still be tarrying on minutiae.
Obviously the actor model is not a panacea. But for my commercial work Elixir -- and thus Erlang's OTP -- has been a true blessing. There aren't many commercial scenarios where OTP is a very poor fit. They do exist but I'd dare saying they are no more than 10-15% of everything you can stumble upon out there.
It's quite sad how fiercely the average HN audience is attacking people who are trying to show an alternative way of doing things.
But if you have the choice, composability always seems much nicer to me and stops me wanting to tear my hair out.
In the sense of being failure domains, OTP "actors", or processes, ARE composable. With very little boilerplate, that is built in as primitive BIFs in the standard library, I can bundle failure domains together and orchestrate them using links, monitors, and supervision strategies, with the ultimate failure domain being a single erlang VM operating inside a cluster of erlang VMs, all supported without third party libraries as a part of the way of doing things.
Then the idea of adding a supervising and observability was a natural addition to these systems.
That said, I think OTP is a great tool for modeling failure domains and I think it does a great job.
To me the answer is: using mutable state is opt-in. I disagree that "mutable state is rampant".
By opting in to the mutable state constructs you are basically saying "I know what I am doing, let me do my work" which is IMO quite fine because "pure" FP languages like Haskell can be a huge hassle when you actually need to deal with the real world.
To me Elixir is a very nice compromise.
It's not about how the Erlang VM is implemented. You could implement it in pure Haskell and compile it so some hypothetical pure CPU. Wouldn't change that part of how you interact with it that is stateful as described.
(And I liked programming in Erlang.)
But maybe we'll talk the same language if you give a few examples. I was under the impression that my parent poster made the point of "but your FP code gets compiled to imperative mutable code so FP is not good" or something. If I was mistaken in my interpretation then we're talking past each other.
Though I don't think anyone ever suggested the actor model (or Erlang) was doing C/C++ craziness.
Have you ever programmed in Erlang?
About your first paragraph: not all databases should be append only, but it would be a good idea to make append-only the default and only deviate for a good reason. (Instead of making mutable the default, and only weirdos go for append-only.)
Yes, exactly. No one was implying that Erlang's model is mimicking those particularly weird languages. The statement was much more narrow.
What is a "typical" FP language? Are Scheme, Common Lisp, OCaml, SML, atypical?
> mutable state is rampant in your average Elixir app
I don't think this is generally true, or at least not on my experience, but I guess it may depend on what would one consider rampant.
What I like of Elixir is not functional programming, it's the extensive use of pattern matching. What I like less is the convoluted syntax of GenServer with all those handle_cast/calls that obfuscate the real code. As a GenServer is usually a way to store a state, they should have had the courage of calling them objects and give them an object like syntax. After all they initially sold Elixir to developers coming from OO languages. If they had given it a Java like syntax maybe it would be 10 or 100 times as big by now.
While GenServer's store state they are, in my mind, more akin to microservices than Java/C++ Objects. They're like microservices, but without needing a separate service bus, global naming system (pg2), etc. Now I do wish Dialyzer/Dialyxer also had better support for checking GenServer handler's and messages, especially intra-process. You have a point the syntax their could be spruced up some perhaps. The process / GenServer paradigm kind of remind me of Smalltalk in a way, where you're passing messages that object may or may not want to respond to. That's not really possible with C++/Java objects.
GenServers do have their own state, but they are used for way more than just storing state. It's probably best to literally think of it as a server in your running application, analogous to a server running on a network.
If storing state is all you're trying to do you might want to look at Agent or possibly ETS.
Further, GenServers come from Erlang, not Elixir. They're intended to model all sorts of runtime properties of code.
This isn't meant as criticism -- I think Erlang/OTP is a brilliant piece of work. But arguably Erlang/OTP is a practical tool that achieved practicality by embracing dogma.
I wonder though if Erlang might have been a footnote in programming history if it weren't for the mindshare that OTP generated. "Simple functional language" is attractive, but "simple functional language with world-class platform" turned out to be a game-changer.
It absolutely would be. There's plenty of "simple FP languages" out there. OTP is very definitely the main selling point of Erlang, and nowadays of Elixir as well.
Yeah but you're using that small subset in 90% of your code.
Look, this is not a thing to worry about in elixir:
def p(my_array):
do_something_with_this_array(my_array)
return my_array
what is my array? I don't know. It could be anything. The company I work for just hired a sloppy python programmer that I don't want anywhere near my code, and you know what, if we change a section of our code to Elixir I am way more willing to have him work on our team.If you hit a performance bottleneck you might as well just use RabbitMQ or Kafka to queue up stuff and process it as it comes along. Or apply back-pressure if your current code allows for it.
I personally think elixir is really special and an amazing fit for any project that needs high IO concurrency.
I would say the only other functional language that has the same bent is Julia, which is "functional for the working scientist". It makes different choices about where to expose state, understandable, since scientific computing has different tradeoffs from systems programming.
That said I have grown an appreciation for more esoteric languages and enjoy seeing the way they handle various problems it's just likely they'll never have a place in my toolkit.
Rust and Scheme have been gateway drugs ha. I found I really like OCaml-y languages.
Now, I’m very interested in Erlang (and to some degree elixir). I’m learning as much as I can about Erlang and the ecosystem; I’m trying to answer the question, “why isn’t Erlang more popular?”
Any guesses? Reasons? (syntax aside)
Habit, confirmation bias, sunk cost fallacy.
Namely: people have gotten a lot of battle scars by working with what pays their bills -- PHP, Ruby, Python, C#, Java -- and they refuse to look at an alternative because that would render their huge time and energy investment moot (in their eyes at least; I don't see why this has to be the case but plenty of people have been adamant about this without giving an explanation).
I've only become a better programmer since I adopted Elixir but I never stopped using other languages.
All of that plus what PG calls "the middlebrow dismissal" are the main reasons IMO. People are just too set in their ways.
I got severely disheartened that 2-3 casual mentions of Elixir were enough for several people in this thread to attack and quickly stereotype me. I think I'll just keep quiet, or at least not mention what I work with. This seems to get the message across much better.
I had originally taken a Programming Language Paradigms class in college with racket, and I really didn't appreciate functional ideas(i.e. syntax is my excuse). I'm now a really big fan of functional language idioms.
Anyone interested should try the futurelearn class, https://www.futurelearn.com/courses/functional-programming-e....