Comment by mcdeltat

4 days ago

IMO the nice thing about Erlang and Elixir is their foundation of representing data is rock solid. Because data is fully immutable, you get a lot of nice things "for free" (no shared state, reliable serialisation, etc). And then on top of that you can add your interfacey, mutable-ish design with processes, if you want. But you will never have oddities or edge cases with the underlying data.

In contrast with languages like C++ and Java where things are shakey from the ground up. If you can't get an integer type right (looking at you, boxing, or you, implicit type conversions), the rest of the language will always be compensating. It's another layer of annoyances to deal with. You'll be having a nice day coding and then be forced to remember that int is different to Integer and have to change your design for no good reason.

Perhaps you disagree with Erlang's approach, but at least it's solid and thought-out. I'd take that over the C++ or Java mess in most cases.

>IMO the nice thing about Erlang and Elixir is their foundation of representing data is rock solid. Because data is fully immutable, you get a lot of nice things "for free" (no shared state, reliable serialisation, etc). [...] >In contrast with languages like C++ and Java where things are shakey from the ground up.

Yes, immutable does provide some guarantees for "free" to prevent some types of bugs but offering it also has "costs". It's a tradeoff.

Mutating in place is useful for highest performance. E.g. C/C++, assembler language "MOV" instruction, etc. That's why performance critical loops in high-speed stock trading, video games, machine learning backpropagation, etc all depend on mutating variables in place.

That is a good justification for why Erlang BEAM itself is written in C Language with loops that mutate variables everywhere. E.g.: https://github.com/erlang/otp/blob/master/erts/emulator/beam...

There's no need to re-write BEAM in an immutable language.

Mutable data helps performance but it also has "costs" with unwanted bugs from data races in multi-threaded programs, etc. Mutable design has tradeoffs like immutable has tradeoffs.

One can "optimize" immutable data structures to reduce the performance penalty with behind-the-scenes data-sharing, etc. (Oft-cited book: https://www.amazon.com/Purely-Functional-Data-Structures-Oka...)

But those optimizations will still not match the absolute highest ceiling of performance with C/C++/asm mutation if the fastest speed with the least amount of cpu is what you need.

  • I think getting "value" vs "objects" right is paramount: this in itself is only a semantic difference yet, but that will allow for a lot of compiler optimizations down the line.

    E.g. the value 5 can't be changed, neither in Haskell, neither in C. A place that stores that value can, which makes the place an "object".

    Mutability fundamentally means identity (see Guy Steele), so I think this is a fundamental distinction.

    As for immutable data, sure, on single threaded code they do carry some overhead, but this may also translate to higher performance code in a multi-core setting due to better algorithms (lockless, or finer grade locking).

> int is different to Integer

Having separate types for these is the problem; not the boxing. C#/IL/CLR handles boxing in a way that doesn't exhibit the problem. If your code is dealing with integers, they are never boxed. They are only boxed when you cast to a reference type such as object. As soon as you cast back to int, you are unboxing.

Java exhibits the problem in a big way because it doesn't have true generics, so you can't have (say) a list of integers or a dictionary with integer values, so they must always be boxed, so you need a separate “boxed integer” type to maintain type safety. In C# you can just use unboxed integers everywhere.

> Because data is fully immutable, you get a lot of nice things "for free"

This. I discovered this by implementing Flow Based Programming[1] (FBP) in Erlang[2] - the FBP is best suited to languages that are message based and immutable data structures. When using a mutable language, messages are constantly being clone as they are passed around. This does not need to be done using Erlang/BEAM.

My feeling is that FBP is a much under-rated programming paradigm and something really worth exploring as an alternative to the current programming paradigms.

My take on FBP is that data is being passed to functionality, as opposed to function being passed to data - the functional programming paradigm, or data and function is passed around as is the case with OOP.

IMHO it makes sense to pass data to functions, particularly in the times of SaaS and cloud computing.

[1] = https://jpaulm.github.io/fbp/index.html

[2] = https://github.com/gorenje/erlang-red

That's also Clojure's approach. It's very nice to program with immutable data at a high level, but for certain things, you just need to use the computer's primitives as they actually are, with all the mess that entails. So, I would say we need languages like C++ and Java (but perhaps we should all be using Rust, which makes the mess much more manageable, despite bringing in a lot of complexity that programmers need to wrap their head around, by for example, making it really easy to represent data, and defaulting to immutability) even if it would be "nice" to avoid them where possible.

Erlang and Elixir (and Clojure), however, lack a static type system, which makes it really difficult to use them at large scale (I am happy if you can provide convincing evidence to the contrary - I just haven't seen any). There's Gleam, which is a beautiful, simple language, that has a very good type system, but unfortunately, it's a bit too simple and makes certain things harder, like serialization (e.g. https://hexdocs.pm/gleam_codec/).

Haskell and Ocaml are more usable, but for some reason are extremely niche. I don't think there's any popular language that's in the "statically typed, functional" school, which I think shows that humans just don't prefer using them (they have been hyped for decades now, yet they just never stick). Perhaps a new generation of these languages will change things, like Unison for example (which stays away from Monads but provide an arguably superior abstraction, Abilities - also known as Effects). I think I would love for that to happen, though as I said before: sometimes you still need to reach out for bare metal performance and you have to use Rust/C++/D or even Java.

  • A lot of functional programming patterns have made their way into newer versions of C#. That obviously doesn't make it a functional language now, but it is also no longer just obviously procedural.

  • Scala might be one of the earliest languages that set out to combine FP with (mutable) OOP, so it probably worth a mention here.