Erlang was the first functional language i really learned and i can definitely attest to the pains mainstream developers go through when switching the paradigm. In fact with Erlang you're jumping two paradigms at once - functional/immutable and actor model of concurrency.
Eventually it clicked and i think learning Erlang was single most impactful thing on my way to becoming "a better developer".
Throw away your best practices of procedural/oop world and unlearn your optimization tricks when diving into functional/immutable. It's a totally different way of thinking about problems.
There's nothing about the ++ syntax that makes it necessarily so. The compiler/interpreter could understand that we're getting a concatenated string and automatically only create one.
Which is the case in several languages.
welcome_user(Username) ->
<< <<"Welcome ">>/binary, Username/binary, <<"!">>/binary >>.
However, the main advantage of using io_lists instead is that `["Welcome", Username, "!"]` has constant complexity with regard to the length of `Username`.If the username came from the database, it's going to be stored in memory before this function is called, and so concatenating must require building a new string.
E.g. no:
A + B + C + D -> AB + C + D -> ABC + D -> ABCD
And for immutable strings, it might not even require to build a new string at all, even if the string is in memory: it can just use a string data structure pointing to the various parts.
(
> Within Elixir, there is no operator overloading, which can seem confusing at first if you want to use a + to concatenate two strings. In Elixir you would use <> instead.
When this popped up, it reminded me of something people try to do often and then have issues with performance. You probably do not want to concatenate strings.
"Yes I do" you'll first think, but actually erlang has a neat commonly used thing to help here.
Let's say you're doing some templating on a web-page. You want to return "Welcome back username!". First pass (a while since I wrote erlang so forgive syntax errors):
Now it's going to have to construct each string, then create a new string with all three. More creation & copying means things get slower.Instead, many of the functions you'd use to write files or return things over a connection will let you pass in a list of strings instead.
Now it's not copying things, which is good. But then we want to put the welcome message into another block with their unread messages. More appending than is good here, concatenating lists is going to take time. Of course, we could put it all in one function, but then we lose re-usability in the templates and have horrible massive functions. While this is a simple example, I hope you can picture a larger case where you'd want to split up the various sections.Anyway, there's a better way of doing this. The functions that take lists of strings actually take lists of strings or other lists. So we can just do this:
You can keep going, nesting this as much as you want. This saves a lot of copying, allows you to split things up and avoids having to keep flattening a structure.So, for people about to get started, try not to concatenate your strings, you can probably save yourself and your computer some time.
For more info on this, you want to search for "IO Lists" or "Deep IO Lists".