The experience of Go vs Elixir

11,377 views
Skip to first unread message

TR NS

unread,
Aug 13, 2013, 7:36:30 AM8/13/13
to elixir-l...@googlegroups.com
So I've been developing a little app that uses a genetic algorithm to determine the most ergonomic layout of a keyboard. I originally wrote it in Ruby, but I needed it to run fast and I wanted to learn a new modern language. So I decided to try two new languages and see how they compare. I choose Go and Elixir. I choose Go b/c it would be super fast --being a lower level language more akin to C. And I choose Elixir b/c it was functional, built on Erlang which is super solid, and b/c it would be easier to code with its Ruby-like syntax.

I have almost finished my experiment, and I can tell you nothing turned out like I expected. The Go code was about a few times faster than the Ruby. But the Elixir code turned out to be many times faster than the Go! I can only conclude this is so b/c Elixir is taking advantage of my multi-core chip automatically, whereas I would have to manually implement concurrent channels in Go to do that --something I have not tried to do yet. In fact I'm not even sure how to work it in and I find it hard to imagine I will be able to get it to be faster than the Elixir code even if I do. Now maybe I am simply doing something terribly wrong in the Go code that I don't get. Regardless, I suspect it is possible to make the Go code run faster than the Elixir code *if I were a programming genius and knew exactly how to write my code perfectly to match the problem set*. That I think is the big take away for me about Go. It is possible to write fast, highly optimized code b/c of its low lever nature, but that also makes it very easy to write unoptimized code too. Elixir on the other hand, working at a much higher level makes you write better code --being functional, that automatically takes advantage of your hardware without jumping thru special hoops. Elixir rocks!

On the other hand, while I expected Go would be no fun to write code in and that Elixir would be nice to write code in (like Ruby), that turned out to be totally the opposite too. Go was actually a pleasure to write in. The concepts are simple and easy to grasp. The code is a little hard to read, but is actually easy to write --you quickly learn the patterns. And even though I had to write some low-level code that I'd normally not have to write in a higher-level language it wasn't hard and it was nice to know exactly what everything was doing. Another big advantage are error messages. Go gives one line for each error with a very understandable explanation, file and line number. That's it. Which made it easy to fix the code one line item at a time. In the end it took me about a day to write the Go version of my program. The Elixir code, well not so much. It took me four days :-( Part of that was obviously adjusting to the functional paradigm. But I think it was also partly due to the language's API being a little confusing. I find myself frequently wondering if some method was in List or Enum (and only after the fact did I learn about Stream). I think also that the syntax, while looking like Ruby, wasn't really much like Ruby at all. It would be like writing Ruby if all you ever used were module methods. Something I always hated about Ruby was having to write File.read(...) and File.join(...) all the time. That's the pattern Elixir uses for everything. Since the Ruby-esque syntax, in the end, didn't prove so nice, I am now wondering what writing in  Erlang would be like. I also started to wonder why Elixir doesn't support a more Ruby like syntax of, e.g. `[1,2,3].each` as a syntax sugar for `Enum.each [1,2,3]`. Given how protocols work, it seems like that should be possible. I think it would have made the experience of writing Elixir code much better and the code would be easier to read too.

So that's my little story about Go and Elixir. And it's rather ironic conclusion, in my opinion.






José Valim

unread,
Aug 13, 2013, 8:57:36 AM8/13/13
to elixir-l...@googlegroups.com
Thanks TR NS for sharing your experience.

If you don't have much functional programming experience, Elixir will definitely require some getting used to. Loops are gone, now you need to think about recursion. Everything is immutable and more. At least, you were able to see first hand the benefits this approach brings and I hope it gives you enough motivation to continue exploring Elixir. :)

I also understand your feelings regarding finding the functions. In Ruby, you have an array, and possibly everything you may want to do with the array is in the array itself, like [1,2,3].each. In functional programming, the data is decoupled from the behaviour, from its functions, so you have different modules to work with the same data. Of course, we try to organize, but you potentially need to look in different places. In your particular case, you should always look at Enum first because Enum is shared in between many structures. If not there, look at List. The Stream is an advanced technique for lazy enumeration, there is no need to worry about it before you are comfortable with Enum.

Finally, regarding the error messages, any poor error message is considered a bug. If there is anything you recall and if you stumble against any poor error message, please open up an issue. We do not take bad error messages lightly.

José Valim
Skype: jv.ptec
Founder and Lead Developer

Saša Jurić

unread,
Aug 13, 2013, 9:43:34 AM8/13/13
to elixir-l...@googlegroups.com
The performance results make me very suspicious. Generally I would expect Go's performance to be similar or better than Erlang/Elixir (note: I am only remotely familiar with Go).

The fact that it was easier to transition from Ruby to Go than to Elixir is not surprising. In my opinion Elixir is much more similar to Erlang than to Ruby, and in that way is very different from typical mainstream OO languages. While Go also introduces some less known concepts, it seems to be more like a "classical" language.

However, I would usually prefer Erlang over Go, because Erlang VM has much longer tradition of powering very large distributed systems, while Go is relatively new. In addition Go has some serious downsides for concurrent programming: bizarre error handling mechanisms, pointers, mutable data structures and cooperative scheduling, all of which make it harder to develop reliable and scalable distributed systems.

I would expect Go to be more appropriate for CPU intensive tasks where some smaller degree of concurrency and parallelism is called for.

Chris-tina Whyte

unread,
Aug 13, 2013, 9:48:06 AM8/13/13
to elixir-l...@googlegroups.com
On Tuesday, August 13, 2013 8:36:30 AM UTC-3, TR NS wrote:
But I think it was also partly due to the language's API being a little confusing. I find myself frequently wondering if some method was in List or Enum (and only after the fact did I learn about Stream). I think also that the syntax, while looking like Ruby, wasn't really much like Ruby at all. It would be like writing Ruby if all you ever used were module methods. Something I always hated about Ruby was having to write File.read(...) and File.join(...) all the time. That's the pattern Elixir uses for everything. Since the Ruby-esque syntax, in the end, didn't prove so nice, I am now wondering what writing in  Erlang would be like. I also started to wonder why Elixir doesn't support a more Ruby like syntax of, e.g. `[1,2,3].each` as a syntax sugar for `Enum.each [1,2,3]`. Given how protocols work, it seems like that should be possible. I think it would have made the experience of writing Elixir code much better and the code would be easier to read too.

Extremely doable in a statically typed language, in Elixir not so much. The problem is that when you have `[1, 2, 3].each` you have to find the correct implementation of `each`, in the correct protocol, in the correct namespace before you can actually run the `each` function. It also happens to be a little difficult if the same `each` name can be used in different protocols that both provide implementations for a given kind of value, so say `Associative.at` would give a different value than `Sequential.at`, and once all you have is `[1, 2].at 1`, which may be both `Sequential` and `Associative`, you can't really infer what kind of implementation to use.

There's also some dynamic resolution overhead because you can't infer the protocol at compile time, that you wouldn't have in a statically typed language.

Alexei Sholik

unread,
Aug 13, 2013, 10:09:37 AM8/13/13
to elixir-l...@googlegroups.com
Could you share your code in Elixir and Go? I'd love to compare the styles.


--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Best regards
Alexei Sholik

Nuttanart Pornprasitsakul

unread,
Aug 13, 2013, 7:23:20 PM8/13/13
to elixir-l...@googlegroups.com
Hi Jose,

You point on the reason why it's hard to find the functions is interesting. I've never realized this before.
This make me understand why, when I was playing around with Clojure, I prefer to find functions from clojure cheatsheet rather than going directly to clojure doc. Because it groups by data type!

Regards,
Tap

TR NS

unread,
Aug 14, 2013, 5:42:23 AM8/14/13
to elixir-l...@googlegroups.com, jose....@plataformatec.com.br


On Tuesday, August 13, 2013 8:57:36 AM UTC-4, José Valim wrote:

Finally, regarding the error messages, any poor error message is considered a bug. If there is anything you recall and if you stumble against any poor error message, please open up an issue. We do not take bad error messages lightly.

I should have been more clear. It's not so much the message as it is the presentation. I can give you an example of what I mean. Here is the Elixir error output I just got:

    $ elixir lib/keyboard.ex
    /file/tab-computing/Projects/corpus/elixir/lib/keyboard.ex:304: variable line is unused
    /file/tab-computing/Projects/corpus/elixir/lib/keyboard.ex:313: variable layouts is unused
    ** (CompileError) /file/tab-computing/Projects/corpus/elixir/lib/keyboard.ex:282: function process_file/2 undefined
        lists.erl:1323: :lists.foreach/2
        /file/tab-computing/Projects/corpus/elixir/lib/keyboard.ex:6: (file)

To make this more akin to what Go would output it would be something like:

    lib/keyboard.ex:304: variable line is unused
    lib/keyboard.ex:313: variable layouts is unused
    lib/keyboard.ex:282: (CompileError) function process_file/2 undefined

The file paths are given relative to the current working directory and there is no stack trace. (A command line option could be given to get the stack trace if needed).

José Valim

unread,
Aug 14, 2013, 6:47:55 AM8/14/13
to elixir-l...@googlegroups.com
I have been looking at those stacktraces for almost 2 years at this point. It requires a fresh pair of eyes to realize how unnecessarily verbose they are. :)

That said, I have pushed a fix to master that prints file paths relative to the current working directory whenever possible. I have not touched the stacktraces yet. Thanks for the wonderful feedback!



José Valim
Skype: jv.ptec
Founder and Lead Developer


Chris-tina Whyte

unread,
Aug 14, 2013, 9:31:54 AM8/14/13
to elixir-l...@googlegroups.com


On Tuesday, August 13, 2013 8:23:20 PM UTC-3, Nuttanart Pornprasitsakul wrote:
Hi Jose,

You point on the reason why it's hard to find the functions is interesting. I've never realized this before.
This make me understand why, when I was playing around with Clojure, I prefer to find functions from clojure cheatsheet rather than going directly to clojure doc. Because it groups by data type!

A little bit off-topic, but I fell in love with the ClojureDocs.org website for quickly finding my way around the standard library :) http://clojuredocs.org/quickref/Clojure%20Core

Would love to see something similar for Elixir.

José Valim

unread,
Aug 14, 2013, 9:34:12 AM8/14/13
to elixir-l...@googlegroups.com
A little bit off-topic, but I fell in love with the ClojureDocs.org website for quickly finding my way around the standard library :) http://clojuredocs.org/quickref/Clojure%20Core

Would love to see something similar for Elixir.

I think this is a great idea. We should start standardizing the docs in a way to support such format. I know Alexei was playing with some ideas along this line.

TR NS

unread,
Aug 14, 2013, 3:26:15 PM8/14/13
to elixir-l...@googlegroups.com
On Tuesday, August 13, 2013 10:09:37 AM UTC-4, Alexei Sholik wrote:
Could you share your code in Elixir and Go? I'd love to compare the styles.

Coming from a Ruby background I'm not doing everything according to prescribed conventions yet (e.g. I use a lot of snake_case in my Go programs), so some of the style might not be quite typical. But here you go:

  https://github.com/tabcomputing/corpus

Please offer suggestions for any improvements. I know there's plenty of room for that. Though being my first program in both of these languages I think its going pretty well.

TR NS

unread,
Aug 14, 2013, 3:38:40 PM8/14/13
to elixir-l...@googlegroups.com

On Tuesday, August 13, 2013 9:48:06 AM UTC-4, Chris-tina Whyte wrote:

Extremely doable in a statically typed language, in Elixir not so much. The problem is that when you have `[1, 2, 3].each` you have to find the correct implementation of `each`, in the correct protocol, in the correct namespace before you can actually run the `each` function. It also happens to be a little difficult if the same `each` name can be used in different protocols that both provide implementations for a given kind of value, so say `Associative.at` would give a different value than `Sequential.at`, and once all you have is `[1, 2].at 1`, which may be both `Sequential` and `Associative`, you can't really infer what kind of implementation to use.

Protocols have order, so I was thinking it would just use the first matching implementation it comes upon. So not everything you can do with a particular data type would be accessible this way. But at least the most common functions would be.
 
There's also some dynamic resolution overhead because you can't infer the protocol at compile time, that you wouldn't have in a statically typed language.
 
So it would have to be done at runtime, not compile time? Why is that? And if so how much overhead?

Chris-tina Whyte

unread,
Aug 15, 2013, 9:40:02 AM8/15/13
to elixir-l...@googlegroups.com


On Wednesday, August 14, 2013 4:38:40 PM UTC-3, TR NS wrote:

On Tuesday, August 13, 2013 9:48:06 AM UTC-4, Chris-tina Whyte wrote:

Extremely doable in a statically typed language, in Elixir not so much. The problem is that when you have `[1, 2, 3].each` you have to find the correct implementation of `each`, in the correct protocol, in the correct namespace before you can actually run the `each` function. It also happens to be a little difficult if the same `each` name can be used in different protocols that both provide implementations for a given kind of value, so say `Associative.at` would give a different value than `Sequential.at`, and once all you have is `[1, 2].at 1`, which may be both `Sequential` and `Associative`, you can't really infer what kind of implementation to use.

Protocols have order, so I was thinking it would just use the first matching implementation it comes upon. So not everything you can do with a particular data type would be accessible this way. But at least the most common functions would be.

This would lead to programs that are fairly difficult to reason about, though, which is not something I'd find desirable, unless we made it an error for a value to implement conflicting protocols.
 

There's also some dynamic resolution overhead because you can't infer the protocol at compile time, that you wouldn't have in a statically typed language.
 
So it would have to be done at runtime, not compile time? Why is that? And if so how much overhead?

Elixir is dynamically typed, so we can't know which protocols a value implements until we know what that value is. Since we don't have the types at compile time, we have the overhead of finding these at runtime. With a statically typed language you could map the operation directly to the correct function at compile time, rather than using a dispatch table. The amount of overhead would depend on the VM and implementation (caching, etc). I assume protocols already have some overhead because of the dynamic typing, but again I'm not familiar with the internals, so I can't really comment on that. It's unlikely that it would make Elixir be as slow as Ruby, but it would be likely slower than the current semantics.

Brendan Tracey

unread,
Sep 18, 2014, 11:24:28 AM9/18/14
to elixir-l...@googlegroups.com
I see this in your code


// Good lord, I have to write my own routine to convert a []string to []interface
// so I can pass the contents of the []string to fmt.Printf.

This is true if you try to pass it is fmt.Println([]string...), but you can pass the slice directly just fine.
http://play.golang.org/p/yS7MVG1wB5

Booker Bense

unread,
Sep 18, 2014, 5:59:07 PM9/18/14
to elixir-l...@googlegroups.com


On Tuesday, August 13, 2013 6:43:34 AM UTC-7, Saša Jurić wrote:
The performance results make me very suspicious. Generally I would expect Go's performance to be similar or better than Erlang/Elixir (note: I am only remotely familiar with Go)



Go out of the box is completely single threaded until you start using channels/goroutines. And even then you'll need to configure it a bit to get it to use all the available cores( google GOMAXPROCS default). It errs on the side of being conservative, rather than expansive.

Elixir on the other hand has many constructs that allow you to use threads without realizing it, and it will use as much of the machine as it can right out of the box. With just a few lines of code, you can create a process with thousands of threads that chews up gigabytes of memory. 

Based on my limited experience with both, in a true apples to apples comparison, my guess is that Go would be roughly similar. However, creating a true apples to apples comparsion with even a simple Elixir program isn't straightforward. 

- Booker C. Bense   

James Ling

unread,
Sep 19, 2014, 10:23:11 AM9/19/14
to elixir-l...@googlegroups.com
New to go and elixir so thought I'd check out the playground link.  Unfortunately I get an error on the snippet.  (It's entirely possible I did something wrong.)

prog.go:9: cannot use s (type []string) as type []interface {} in argument to fmt.Println
 [process exited with non-zero status]

mike myers

unread,
Sep 20, 2014, 12:25:51 PM9/20/14
to elixir-l...@googlegroups.com
XML putting version in header is good, Its the same as HTML doctype (obviously because HTML is SGML, ancestor of XML) that help browser identified HTML version in the web page. Then render the page according that version. I Think, on that case, web browser is like compiler. Its also good to work with xml.

Matt Widmann

unread,
Dec 21, 2014, 6:01:58 PM12/21/14
to elixir-l...@googlegroups.com
Elixir on the other hand has many constructs that allow you to use threads without realizing it, and it will use as much of the machine as it can right out of the box. With just a few lines of code, you can create a process with thousands of threads that chews up gigabytes of memory.  

I'd like to see these few lines you claim eat up gigabytes of memory. 

You cannot create thousands of threads in the Erlang VM because it uses processes. The Erlang VM will create 1 thread for each scheduler (which by default I believe is one per core, so an 8 core machine would have 8 schedulers).  Each scheduler will run code in thousands or millions of processes (I personally have created 10 million on my machine without using up hardly any memory or CPU at all). Erlang was created in the '80s where memory was extremely scarce, it doesn't make any sense if this were true.

Greg Young

unread,
Dec 21, 2014, 7:17:50 PM12/21/14
to elixir-l...@googlegroups.com
Erlang nor elixir create thousands of threads. You may have thousands
of processes but processes do not map to actual threads. I would
really consider doing some more research as opposed to fanboyism.
> --
> You received this message because you are subscribed to the Google Groups
> "elixir-lang-talk" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to elixir-lang-ta...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.



--
Studying for the Turing test

Greg Young

unread,
Dec 21, 2014, 7:18:59 PM12/21/14
to elixir-l...@googlegroups.com
Sorry didn't see yours as well.

Here is a good little webcast on it to show a bit of how it works
https://www.erlang-solutions.com/resources/webinars/understanding-erlang-scheduler

Bruce Tate

unread,
Dec 22, 2014, 8:51:38 AM12/22/14
to elixir-l...@googlegroups.com
This is a great example of what's great about Elixir vs. C/Go/Next. 

When your code is organized the right way, and you can do a much better job removing the unnecessary latency. I think we're going to start to see many measurements like this. 

When I wrote Seven Languages, Steve Dakorte told me about many measurements of Io vs. C. Same story, though C was a much faster lower level language, though Io is pretty slow. The actors made all of the difference. 

A similar story. There's a highway with a 65 MPH speed limit. My wife always takes it. There's another road with a 45 MPH speed limit. The back way. I always beat my wife home. It's the lights, of course. 

-bt

Bruce Tate

unread,
Dec 22, 2014, 9:04:07 AM12/22/14
to elixir-l...@googlegroups.com
Wow. Lots of grammar problems in that post. Can you tell it's early?

-bt

Onorio Catenacci

unread,
Dec 22, 2014, 11:13:32 AM12/22/14
to elixir-l...@googlegroups.com
Great analogy (65 MPH Highway vs. 45 MPH Surface Road) Bruce!  How fast you can potentially go often makes little difference in practice.

--
Onorio

Alex Shneyderman

unread,
Dec 22, 2014, 6:47:27 PM12/22/14
to elixir-l...@googlegroups.com


On Monday, December 22, 2014 8:51:38 AM UTC-5, Bruce Tate wrote:
This is a great example of what's great about Elixir vs. C/Go/Next. 

A similar story. There's a highway with a 65 MPH speed limit. My wife always takes it. There's another road with a 45 MPH speed limit. The back way. I always beat my wife home. It's the lights, of course. 

There are lights on the highway? I am confused ...

José Valim

unread,
Dec 23, 2014, 3:43:11 AM12/23/14
to elixir-l...@googlegroups.com
When I was in Colorado, yes. You had intersections so cars from small cities or small neighborhoods could cross or join.

True story. 
--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--

Peter Hamilton

unread,
Dec 23, 2014, 11:20:58 AM12/23/14
to elixir-l...@googlegroups.com
In the US (at least the west) a "freeway" has no intersections while a "highway" may have occasional intersections. Many people just call everything a highway though.

I also suspect a looser interpretation of the speed limit on the back roads.  :)

Russ Mack

unread,
Dec 23, 2014, 11:18:58 PM12/23/14
to elixir-l...@googlegroups.com
Back on the subject of error messages... As a noob, I'm enjoying Elixir, but find the error message can be quite tough going.
I don't usually read Go error messages.  I read the file name, the line number, then before reading the error description I switch to the code window knowing I'll usually see the error immediately.
Elixir's error messages often leave me scratching my head.  I've tried to think up some examples:

# This error is exact.
# Compare this to the last example `ErrorBad` - same error, different syntax.
# Although, don't know what the `try` is.
defmodule ErrorBest do
    def my_func(a, b) when a > b,  dO: :ok  # unexpected keyword dO in try
    def my_func(a, b) when a < b,  do: :ok
    def my_func(a, b) when a == b, do: :ok
end

# This error is easy to locate, even if it's not a function, it's understandable.
defmodule ErrorOk do
    def my_func(a, b) when a > b,  do: o :ok  # function o/1 undefined
    def my_func(a, b) when a < b,  do: :ok
    def my_func(a, b) when a == b, do: :ok
end

# This error is easy to locate, but why is the syntax error `before`?
# Fine in this instance, but I fear that in other contexts could this lead astray?
defmodule ErrorSuspect do
    def my_func(a, b) whence a > b,  do: :ok  # syntax error before: whence
    def my_func(a, b) when a < b,    do: :ok
    def my_func(a, b) when a == b,   do: :ok
end

# This error gives an unhelpful line number, and
# should rather be raising the same error, `unexpected keyword dO in try`, as in the first example `ErrorBest`.
defmodule ErrorBad do
    def my_func(a, b) when a > b dO
        :ok
    end
    def my_func(a, b) when a < b do
        :ok
    end
    def my_func(a, b) when a == b do
        :ok
    end
end  # unexpected token: end


Another error: cannot invoke remote function Module.get_attribute/3 inside match
Although I know what this refers to, I have no idea what `Module.get_attribute/3` is, which is a slight poke in the eye.

As mentioned, this is from a noob point of view, with no Erlang experience, and only some Scala as partly functional experience.

José Valim

unread,
Dec 24, 2014, 3:58:11 AM12/24/14
to elixir-l...@googlegroups.com
Hello Russ!

We do worry a lot about error messages. The errors you complain come from the parser and there isn't much we can do at this point besides a full rewrite. :(

I am also interested in this particular message:

"Another error: cannot invoke remote function Module.get_attribute/3 inside match"

How to reproduce it? Finally, any feedback regarding the error message format itself?



José Valim
Skype: jv.ptec
Founder and Lead Developer

--

Russ Mack

unread,
Dec 24, 2014, 10:17:37 AM12/24/14
to elixir-l...@googlegroups.com, jose....@plataformatec.com.br

Hi José,

I had the error message noted, but not the culprit - a simple syntax error.
I thought it was List.count, but that gives a precise error message:
cannot invoke remote function List.count/1 inside guard
At the time, I wasn't aware of, or had forgotten about `length/1`, so I thought I might not be able to achieve the desired guard, but it was quickly found.

defmodule MatchError do

    @my_const = 42  # Oops.

    def main() do
        my_func(10, @my_const)
    end
    def my_func(a, b) when a > b,  do: a
    def my_func(a, b) when a < b,  do: b
    #def my_func(a, b) when List.count(a) == length(b), do: a
end

Gives:


cannot invoke remote function Module.get_attribute/3 inside match

Quicker for noobs would be eg: Syntax error in attribute definition.
`match` refers to the fact that with an `=` the parser thinks that's an expression rather than an attribute definition, I think.
This looks a little to me like the same issue as the `ErrorBad` example in my previous post, in that if the order of the parsing was changed then a different error would be identified first and returned.
That is, in the `ErrorBad` example, if the parser found unexpected keywords before extra `end`s that would be more helpful, even though it does seem intuitive to first check the basic structure, and is probably necessarily first.
In this match error example, if the parser found attribute definition errors before match errors, this would be more helpful.
I think I'm understanding your parser rewrite comment.  But I'm not much beyond the brainfuck language level of language writing, so get out your bucket of salt.
I'm wondering if the `ErrorBad` example, highlighting as faulty the line of an effect rather the cause, that possibility starts to creep into one's mind with other errors.  So if I don't spot the error immediately in the mentioned line, I start looking at associated locations, starting a wild goose chase.
It's Rumsfeld territory [0] - as a noob, I know I don't know what I'm doing, so I don't know what I know and what I don't know, known unknowns, and knowing there are unknown unknowns, so I doubt, wonder and fumble.
The Go error messages having a really quick turn-around time greases the wheels nicely.
This has turned into a useful reflective meditation, if nothing else!

[0] http://en.wikipedia.org/wiki/There_are_known_knowns

José Valim

unread,
Dec 24, 2014, 11:14:19 AM12/24/14
to elixir-l...@googlegroups.com

defmodule MatchError do

    @my_const = 42  # Oops.

    def main() do
        my_func(10, @my_const)
    end
    def my_func(a, b) when a > b,  do: a
    def my_func(a, b) when a < b,  do: b
    #def my_func(a, b) when List.count(a) == length(b), do: a
end


Thank you, we will improve this message.

It's Rumsfeld territory [0] - as a noob, I know I don't know what I'm doing, so I don't know what I know and what I don't know, known unknowns, and knowing there are unknown unknowns, so I doubt, wonder and fumble.

Right, but that is exactly when you are more likely to run into "silly" errors and the bigger the need to have better error messages.

I have always said that, if you see an error message in Elixir and you don't understand it, it is a bug. Some of those can be very hard to fix, but I am confident we can do a very good job in many of them.


Booker Bense

unread,
Dec 30, 2014, 12:52:40 PM12/30/14
to elixir-l...@googlegroups.com


On Sunday, December 21, 2014 3:01:58 PM UTC-8, Matt Widmann wrote:
Elixir on the other hand has many constructs that allow you to use threads without realizing it, and it will use as much of the machine as it can right out of the box. With just a few lines of code, you can create a process with thousands of threads that chews up gigabytes of memory.  

I'd like to see these few lines you claim eat up gigabytes of memory. 

Um, I didn't mean that in a bad way, I meant that the language provides abstracts
that allow you to create large data structures easily. I did not mean it as overhead. 

For example, check out an early version of this code. Admittedly, it was an error on my part to read the entire
files contents into memory rather than streaming each line, but it was just a few lines. 


Basically, take any large Stream and dump it straight into an Enum. It's an obvious thing
to do and can chew up a lot of memory with big files or other large data sources.

 

You cannot create thousands of threads in the Erlang VM because it uses processes. The Erlang VM will create 1 thread for each scheduler (which by default I believe is one per core, so an 8 core machine would have 8 schedulers).  Each scheduler will run code in thousands or millions of processes (I personally have created 10 million on my machine without using up hardly any memory or CPU at all). Erlang was created in the '80s where memory was extremely scarce, it doesn't make any sense if this were true.

I mispoke, I meant Elixir processes, which aren't process or system threads. It would probably help things if we had a different word for them. While they
are more like processes than threads, they aren't either and I find it quite confusing personally to call them processes. Perhaps "spawns" would be a better
word. 

- Booker C Bense 

Jose Luis

unread,
Jan 3, 2015, 4:15:03 AM1/3/15
to elixir-l...@googlegroups.com
In my opinion process is a good name.

They dont share state, they dont share memory, they are planned preemptivly.

Yes they are not system processes, i mean, OS processes. They are BEM, Erlang VM processes.

Jose Luis

unread,
Jan 4, 2015, 6:48:20 AM1/4/15
to elixir-l...@googlegroups.com
In go they use the term "gorutines".

They are not processes because they share memory.
They are not threads, because they are not preemptive.

Gorutines look like preemptive but they are "automatic-cooperative".

In windows you also have fibers. They are fully cooperative and lighter than threads (therefore lighter than OS processes). Gorutines aren`t fibers (you don't need to inform about cooperation, I'm not a windows programmer...).

In Rust, you can choose, "automatic-cooperative" (similar to gorutines) and light, or fully preemptive but heavier (implemented as native threads).

In Akka/Scala, Akka/Java (an actor implementation, copying the Erlang concepts, for JavaVM), you also work with "automatic-cooperation".

In Go, Rust, Akka/Scala-JavaVM you can call native code easily or just a non async lib. This combination produces some important risks (important because is very easy to make mistakes callings sync libs or native code).


In Elixir/Erlang, we don't have to be worried about this. Only in very specific and very low level rare cases some people have to deal with this risks.


Booker Bense

unread,
Jan 5, 2015, 12:17:11 PM1/5/15
to elixir-l...@googlegroups.com
Yeah, I realize this horse has already left the barn, but in my brain names tend to be very sticky,
and I always think of the results of a spawn call as threads although nobody else does.  

So I'll try my best not to use threads in this list, but I may slip. I really do mean Erlang VM processes. 

- Booker C. Bense

Greg Vaughn

unread,
Jan 5, 2015, 12:43:41 PM1/5/15
to elixir-l...@googlegroups.com
When I was first learning Elixir, which was also my first introduction to BEAM, I mapped BEAM's "process" to "thread" in my mind too. It seemed like a pedantic distinction, but I just went along with the culture. Now, I've changed my mind completely and find it to be of the utmost importance to make the distinction. Thread-based/shared memory/mutex concurrency is fundamentally a dead end and the computing industry couldn't move away from it fast enough to suit me. The word "process" now means to me the shared-nothing/messaging-only model of concurrency, which is actually possible to reason about at scale.

-Greg Vaughn
Reply all
Reply to author
Forward
0 new messages