Learning Elixir, frst impressions ( plz don't kill me ! )

Very good replies so far, but I’d like to step back for a brief historical overview that might help frame how you view Elixir in relation to other languages you know.

It is fundamentally a “concurrency oriented” language. Joe Armstrong (co-creator of Erlang) has described Erlang as such. Those design forces are reflected deeply in the VM itself, and it’s a property all languages on the BEAM share. The original reason for Erlang’s existence is that Ericsson needed a language to meet specific business needs. Fault tolerance was high on the list. Fault tolerance led to supervision which needed isolated processes (and basically independently discovering the actor model). Isolated processes needed immutable data and first class functions and tail call optimization. Thus functional features fell out of more primordial concerns. All of this pre-dates the creation of Haskell.

If you’re one that thinks proper “functional programming” has to include monads and currying, etc., then mentally put Elixir in a different language category or else you’ll remain frustrated. We have alternative means of solving similar concerns. They’re not as theoretically pure, but in practice work out well.

Everything I’ve said before applies to any language on the BEAM, so now let’s speak to Elixir specifically. It differs from its parent language of Erlang by adding Lisp-style hygienic macros and Clojure-style protocols. It adds the pipe operator from the ML family of languages and intentionally puts the subject first to optimize pipe use. It offers a superficially Ruby-esque syntax in some places (and differs strongly in others). It adds web development style tooling in libraries/packages via hex and in building/compiling via mix. There’s more, but that’s a good first group of things to digest.

There’s more to be said about intangibles like community. I find it quite interesting that you worry enough to put “plz don’t kill me” in your subject, and I’m pleased to see in the replies no inclination to even consider doing that.

Welcome!

20 Likes

Yes the Elixir/Erlang community only kill their children and they use supervisors to do that :grin:.

If you want to compare promises with simple elixir have a look at two of my projects that solve the same problem {:ok, “the Elixir one is not quite finished”}

3 Likes

Wow, so many yummi replies !
This is going to be quite huge !

This truly breaks my heart. There is a huge marketing effort in making Elixir the new cool FP language but it lacks basic FP features because it is not a real FP language, it only borrows some concepts. I am not sure how I feel about the implications of your comment, but it makes sense and is quite unsettling to me.

Normal syntax like when you call a normal function. A JS example:

const add = x => y => x + y;
const increment = add(1);
console.log( increment(2) );
console.log( add(1) (2) );
//so on

In Elixir, when you call a normal function, you don’t call it with the .(). For example:

def add(x, y) do
    x + y
end
# stuff happens
add(1, 2) #instead of add.(1, 2)

Now this is mind blowing. A FP language that doesn’t do composition. Where can I read more about this ( as in, why no composition? a limitation from Erlang ? something else ? ) ?

Correct! Thanks!

Well, expected errors are usually handled via {:error, reason} tuples you match against.

Exceptions are usually only used for errors you do neither expect, nor could recover from.
Ahh, so for Failures ( errors you expect ) you use pattern matching, and for Exceptions ( errors you don’t ) you use the try / rescue construct. I think I get it!

Which is still not a for loop. To be honest, I love the fact Elixir misses a for loop construct! (IMO, a good thing).

Currying, Partial application and Monads are tools. You can choose to use them or not. The problem is for people who want to use those tools, they can’t. So why use Elixir ? You have other very strong FP languages out there with a bigger toolkit to use :smiley:

Quite interesting. Where can i read more about this?
Also, I am already checking Exercism.io :stuck_out_tongue:

I think I get it, very well put!

So you are saying that people usually use the Either Monad, but without realizing it. The issue remains, but as long as I can import a Monads library I won’t mind :stuck_out_tongue:

Now, I would have to disagree here. As someone who has been doing FP in JS for over a year I can tell you there are solutions to this. You may not have Tail Call Optimization implemented, but you can do it yourself in your functions and it’s rather simple once you get the idea. I honestly can’t remember the last I used a ´for loop´ in JS, unless it was for something really performance intensive and synchronous.

A really enjoyable reading. I wouldn’t call it pushing the limits, for me it was merely the start. Purescript and the others are fine, but with vanilla JS and using a couple of libraries you can do pure FP quite easily ( ramda, sanctuary, fluture, folktale, etc ). Those push the limits :stuck_out_tongue:
That’s how I have handled pure FP in JS until now.

This is confusing. A previous user just said Elixir doesn’t really do function composition. I still am quite surprised with this…

Indeed, my comment was simplifying the true capabilities of Elixir. Your post is gold !

def reverse( list ) do: reverse( list, [] ) end
def reverse( [], reversed ), do: reversed
def reverse( [head | tail ], reversed ), do: reverse( tail, [ head | reversed ]) 

Here is an example of 2 functions called reverse, both with the same name and same arity. Now, if I get it correctly, you mean to tell me that this only works because of pattern matching, and that the function’s signature is not being taken into consideration?
I guess I can live with that.

Well, for me its purity keeps people from calling me at 3 AM in the morning because our app crashed with a side effect or worse, got into an inconsistent state because of one. I am not saying Elixir should emulate Haskell ( it was merely an example of a language in my post ) but I do believe Haskell has some things Elixir could really use.

Ahh yes, I am well aware of the familiarity bias. That is not what is stopping me, being familiar with problems empowers you to overcome them. But I do believe that assessing syntax as irrelevant is irresponsible at best. If you don’t believe me, I challenge you to use http://www.jsfuck.com/
:smiley:

In other words, syntax matters :stuck_out_tongue:

My dear, I wouldn’t dare. I have come a long way to know when that is happening :stuck_out_tongue:
That is why I joined this forum with all these wonderful people. I want to learn Elixir. Not to write JS using Elixir.

I completely agree !

Let’s just say that my direct approach and my sense of humor don’t always find the best friends in forums. I don’t insult people and I always try to be respectful and light hearted, but sometime that’s not enough. I really need to get along with this community, so I am just trying to be careful.

Thanks !

Will do!

1 Like

Now, I would have to disagree here.

My point was that the JavaScript runtime isn’t designed to cope with unbridled recursion regardless of the available tricks. Any for loop avoidance is largely implemented via higher order functions which hide the implementing iterative loop away from you.

using a couple of libraries you can do pure FP

  • those libraries can cheat under the hood (not that it’s necessarily a problem) to align with the sensibilities of the JavaScript runtime
  • and they can’t ensure that your code is pure compared to a compiler

A previous user just said Elixir doesn’t really do function composition.

Not out-of-the-box.

This adheres to our general principle that we do not provide built-in mechanisms; we provide primitives with which mechanisms can be built.

defmodule Demo do

  def f(x) do
    x + 2
  end

  def g(x) do
    x * 3
  end

  # dynamic composition with a closure
  def compose(g,f) do
    fn (x) ->
      x
      |> f.()
      |> g.()
    end
  end

  # "static composition"
  def g_comp_f(x) do
    x
    |> f()
    |> g()
  end

end

x = 5
fun = Demo.compose(&Demo.g/1,&Demo.f/1)

IO.inspect(fun.(x))
IO.inspect(Demo.g_comp_f(x))
$ elixir demo.exs
21
21
$

Here is an example of 2 functions called reverse.

No it is not. Those are two function clauses belonging to the same function. They are functionally equivalent to:

def reverse(list, reversed) do
  case list do
    [] ->
      reversed

    [head|tail] ->
      reverse(tail, [head|reversed])
  end
end

See

I do believe Haskell has some things Elixir could really use.

Why don’t you use Haskell then? There are plenty of forum users here who know Haskell and use it whenever possible but still find Elixir/Erlang useful under many circumstances. I’d personally prefer if there was static typing with a real type system but it’s absence isn’t a showstopper (and I blame JavaScript for getting me used to that fact).

But I do believe that assessing syntax as irrelevant is irresponsible at best.

It’s meant as a “stop whining and get on with the business at hand” notion - and we are talking about Elixir/Erlang here - not JS syntax hampered by backward compatibility considerations.

3 Likes

Reading through this @Fl4m3Ph03n1x your comments and replies really don’t seem to be made in good faith.

You call it a direct approach and your sense of humour but honestly you are just being rude and it is not surprising you find it difficult to make friends on forums with this approach.

5 Likes

Generally if you are having a serious discussion, or with people you don’t know, it’s usually best to avoid humour - unless you’re certain it won’t be taken the wrong way. (Going by your comment above though, it appears this isn’t the case in your experience… that should probably be telling you something :lol:)

I’m also struggling to see what the purpose of this thread is. Are you trying to point out that Elixir is ‘different’, lacks some FP stuff, is peculiar in places? If so you’re not telling us anything we don’t know.

As has been pointed out by others, Elixir is not trying to be like Haskell (or other similar languages). It is at its most basic, simply trying to be a modern version of Erlang with some key influences from Ruby and other languages thrown in. Erlang itself was built with a very specific job in mind - one that it excels at. You could argue that Elixir is merely trying to be as close to a perfect language as its creator wanted - constraints allowing. It just happens that so many of us love it as well, warts and all.

If you’re wondering why, take a look at this thread:

And then if you are still excited about the language, I recommend learning it by reading some of the excellent books available - here are some recommendations based on what I have read or done myself, although there are of course many more (see: #learning-resources:books and #learning-resources:courses)…

If after reading the Why Elixir? thread you’re not enthused or you feel the language is not for you - that’s cool too. Good luck on whatever you decide to adopt.


As a general note, if you’re new to a community it’s a good idea to put yourself in the shoes of others - and ask yourself how your comments/thread might come across. If you’re genuinely interested in helping the language, or hearing the thoughts of others, diplomacy and tact (not humour and unfair or immaterial critique) is usually the best way to achieve your goal.

11 Likes

Ahh I love my programming drama in the morning.

Just wanted to point out this, since no one else has, I think. Your default value slashes are the wrong way around. It would be def foo(x \\ 1, y \\ 2), which would not be mixed up with a typical C++ style comment. But even if it was //, there’s plenty of other things you can mix up in Elixir if you think all languages look like C++. :stuck_out_tongue:

2 Likes

Dude, Erlang has been like this for more than 3 decades. Elixir just adds different kind of syntax and toolings and web frameworks on top of it. We say Elixir as functional programming language, because it has no class, no object, no pointer as well. Just simple functions, in and out.

Jose Valim wants to bring the power of Erlang and OTP, but he wants it to be like that, the Elixir. The surface syntax looks like Ruby, Phoenix web framework kinda looks like Rails.

I’ve been coding Elixir in the last 4 years, and haven’t found a single monad or currying or for loop (even Haskell don’t have for loop as well, CMIIW). I love Elixir, because it has no monads and other functional aspects that are really hard to explain to other devs coming from OO/imperative.

And that is, Elixir code should be optimized for reading and understanding. There is a huge amount of effort on making an official Elixir code formatter.

If you are looking for pure functional programming language, I’m sorry, then Erlang and Elixir are probably not for you.

Well, TBH even Java that is marketed as OO from a very long time ago, is not pure OO. You want pure OO? Go get some Smalltalk.

3 Likes

Looking for OTP tutorials try Learn You Some Erlang for Great Good (online or as a book).

OTP is covered in most introductory/intermediate Elixir books.

If you are looking for pure functional programming language

In my understanding that is the silliest mistake, a developer can make: to look for the language to be fully compliant with some specific fashionable/hipe paradigms. What is the benefit of being “pure functional programming language”—well, none.

4 Likes

This post literally compelled me to write a long answer, so I’d drop the link to it here fwiw.

3 Likes

Careful now. I am not here to insult anyone I am just expressing my first impressions while trying to get a grip of the true nature of Elixir.

If I had to pin point the problem with my post it would be that I had all these notions and expectations on what features a FP should have and then when I realized Elixir didn’t I felt frustrated and I think that shows on the original post.

However, jumping from that to you are not making posts with good faith is a long jump and one that I believe is rather unfair. I am not here to tell you that Elixir sucks and language X is better or the other way around. I mean, going to an Elixir forum and complain that Elixir is bad because reason A, B, C would be rather unproductive, don’t you think?

Try to give me some time and know me better, who knows, you might like me ! ( or not? I’ll leave that up to you :stuck_out_tongue: )

And now, after reading over 20 replies I completely understand this :smiley:
Also, thanks for the resources, can’t wait to get started !

Easy there champion! That is in the " Elixir Weirdness ( aka, stuff you will eventually get used to )" section. Which means that it is only strange to me because of my background. Which means I am aware of it, and thus it’s only a matter of getting used to. Not a big deal :smiley:

I just wondered if someone else from a similar Java / C# / Javascript background had the same experience or thought when they started with Elixir.

This is actually something I value a lot. But while watching Thinking like an Erlanger I got this idea that syntax is secondary ( no one cares if it looks pretty or readable ) and that thinking is the principal part. As in protocols matter, how you implement them doesn’t ( as long as they work ).

Perhaps I miss-interpreted something? Could you show me some light on this ?

You are correct Sir ! ( also why I eventually left Java and God forbid I ever return … )

This OTP thing looks important. Will look into it !

Replied in your article :smiley:

If you want to use the list Monad, you could use the base syntax [1, 2, 3] as the unit mechanism for putting values into the monad, then use the functions of the List or the Enum modules to manipulate the values in the monad. You could bind multiple functions together using the pipeline operator if you like.

If you want to use a the Maybe or Result monad, a common technique is to use a tuple. A tuple of {:ok, value} might represent the Some or Just value, while either a tuple of {:error, term} represents. If you like you could also use {:some, term} and :none as the appropriate values. To bind them together you would commonly use a with statement in order to get the short-circuit behavior common to that monad. Something similar could be used for most variations on the State monad.

If I wanted to use a “clock face arithmetic” monad, for example, I would use judicious application of integer division and the rem function (for modulo arithmetic). I would probably bind the functions together using the pipeline operator again.

My point, of course, is that Elixir is currently full of Monads and there is nothing that would stop any particular developer from creating any monad they need to use. To your point there no concept of a Monad “typeclass”. There is not type-based facility, with syntax support, for treating Monads as a first-class construct, but there is plenty of facility to use monads in the language.

3 Likes

That’s good enough for me!

Weird is in the eye of the beholder, of course, but let me see if I can explain why this is the case. Elixir uses separate contexts to bind named functions and variables. This, as I understand it, means that Elixir is a “LISP 2” language. Here is a code sample:

defmodule DotSyntaxExample do

  def ambiguous(x) do
    IO.puts("I am in the ambiguous named function #{inspect x}")
  end

  def entry_point() do
    ambiguous = fn (y) -> IO.puts "I am in the ambigous variable. #{y}" end

    ambiguous("Hello")
    ambiguous.("World")
  end

end

DotSyntaxExample.entry_point()

# λ <521>$ elixir Ambiguous.exs
# I am in the ambiguous named function "Hello"
# I am in the ambigous variable. World

In this contrived example, when you are in the context of the entry_point function, there is a binding in the space of named functions for ambiguous and the function itself creates a binding to a variable named ambiguous that happens to lead to an anonymous function.

At the call site I need to tell the system which of the two I am interested in calling, the named function, or the value in the variable. For that reason, Elixir uses the .() syntax to indicate that I want to use the variable binding instead of the named function binding.

2 Likes

What I mean by weird, is that when compared to how you call normal functions in Elixir. Your example illustrates this in perfection:

 ambiguous("Hello")
 ambiguous.("World")

Now I get why you need .() in this example. It is a disambiguation.
However when currying ( in he article I presented and in here ) it seems that the only way to use dynamic functions is to bind them, which results in the syntax .(), instead of the more natural ().

But perhaps I am mistaken? Perhaps there is a way to call anonymous functions when currying that doesn’t require binding ? ( and thus promotes the usage of the () syntax ? )

About your serach at hex.pm, I think the most complete package is https://github.com/expede/witchcraft

1 Like

People seem to forget that a curried function is a workaround for the constraint in lambda calculus that a function can only have one, single argument. So in its original form (((f(1))(2))(3)) was necessary instead of f(1,2,3).

Languages like Haskell and OCaml popularized a notational convenience where you can use forms like f(1) and f(1,2) to return another function. But somehow people conflate that notational convenience with “currying”.

What is worse is that the obsession with currying seems to obscure the fact that “partial application” is the useful and powerful idea - which can be implemented simply by capturing available parameters inside a closure and returning a function that is ready to accept the remaining parameters.

As far as I’m concerned partial application is the meat and potatoes - currying is a mere frill.

11 Likes

These two statements are curious and interesting to me. “Horrible” is obviously a subjective opinion, and, in my opinion, a rather strong superlative to paint the entire API with. I’ve never seen anyone else mention that the the position of parameters in a function call being a “basic concept of FP languages”.

Is it somehow tied into your apparent penchant and desire for partial application?

I’ve not really had any strong problems using the Elixir API. It’s something I do have to think about switching back and forth between Elixir and Elm. Even so, I certainly wouldn’t categorize it as “horrible” myself so I’m genuinely curious to know, what do you find so objectionable?

That topic does come up regularly but because on the BEAM different functions can have the same name as long as the arity differs, creating Haskell-style “compile time notational currying” is basically out of the question anyway.

(In Bucklescript, which supports curried functions, parameter position was an ardently discussed topic).

1 Like