Live data from Hacker News

Comparing Elixir and Go

blog.codeship.com

81–90 of 202 posts

Re: Comparing Elixir and Go

#81
post #60
post #30

Earlier quoted context omitted.

Anyone with a decent CS degree should be able to produce working compilers and interpreters, otherwise it wasn't a decent degree. Of course, writing very good ones is a different matter.

> Anyone with a decent CS degree should be able to produce working compilers and interpreters, otherwise it wasn't a decent degree. Which would be useless for production without several years of maturity, a tools ecosystem, and a community adopting them -- and of course continued support. So this is mostly theoretical.

So now compilers should only be written, if v1.0 is production ready?!

> So this is mostly theoretical.

No, it is setting the facts straight about the widespread ignorance of mixing languages with implementations.

Re: Comparing Elixir and Go

#82

Author here. This was published a week earlier than expected so just a heads up that there are a couple of edits coming.

Maybe already fixed, but here are a couple things I noticed: Go methods have to be defined in the same package as their receiver's type. As a result, you can only add methods to your own types, not someone else's. Also, the article claims that Go interfaces are similar to Elixir's pattern matching but I don't see a resemblance. Perhaps clarify that?

But you can define an interface that matches someone else's types and then attach the method to it.

The main similarity I was going for was the way that an interface fits anything that matches it, rather than being directly implemented by the type. A method could be attached to an interface that matches a struct with two specific variables while Elixir could define a pattern on a function that worked for any struct that contained those two variables.

They are both doing a similar thing a different way.

Re: Comparing Elixir and Go

#83
post #8

Earlier quoted context omitted.

This is how myths are created and perpetuated. This claims from a study of a particular model of Ericsson's ATM switch whose software was written in Erlang. A can tell you for sure that: * Ericsson has other switches and other telecom equipment whose software is written in C++ * other companies (Nokia, Cisco, Alcatel etc.) also built similar complex telecom equipment whose software was in C++ I'm going to bet that at…

But suitability is a huge factor here. The point isn't that "nine nines" reliability cannot be achieved in C++ or whatever, it's that it's significantly harder and costlier to achieve. But also: Of course a language creates reliability. Null pointers are impossible in Erlang, whereas they are provable impossible to avoid in C++. So people bring this up because Erlang programs are pretty much reliable by default (assu…

> Null pointers are impossible in Erlang, whereas they are provable impossible to avoid in C++.

They are trivially possible to avoid in C++ as you do not have to use raw pointers. References, value types, custom non-null smart_ptrs, etc.

Re: Comparing Elixir and Go

#84

I still don't understand what all the hype is about pure functional programming. Sometimes mutations are useful. There are lot of good programming design patterns which depend on mutations. Also, always copying objects by value every time you call a function seems very expensive; especially if you're dealing with very large objects/structs/maps/strings which have to be processed by many functions.

In practice, functional languages typically use persistent data structures, which represent collections such as dictionaries, vectors, sets internally as trees. Adding, removing and updating data requires changing a path in this tree while sharing the remaining of the structure. It is not a deep a copy and a really large map won't be very expensive to modify. Rich Hickey has a good talk on the matter: https://www.youtube.com/watch?v=dzP05hEDNvs

There are also optimizations that are straight-forward to understand and implement once you assume immutability. For example, take the following function in Elixir:

    def some_list do
      [1, 2, 3]
    end
Because a list is immutable, when code is compiled we put such data structures that appear literally in the code into something called a literal pool. Anything in literal pool is loaded when the code is loaded. Now every time you call that function, we return the same list and we don't create new instances/copies on every call. That list may be embedded in a map, another list, whatever, and still point to the same memory representation because nothing will ever change it.

Here is an example that leverages this in the context of a web framework for great rendering performance https://www.bignerdranch.com/blog/elixir-and-io-lists-part-2.... While this is definitely achievable in other languages, we get it pretty much for free with immutable data structures and it is a natural mechanism to reason about. IanCal talked about it a couple comments above: https://news.ycombinator.com/item?id=13498532

Regardless, you are still correct when you say that mutations are useful. There are many algorithms that will be more performant if implemented on top of mutations. Luckily, most functional programming languages, including the pure ones, provide mutable data structures or memory references for such cases. For example, when working on GenStage/Flow for Elixir, I optimized the hot paths by using mutable dictionary and called it a day.

Many claim immutable data structures are a better "default" for writing software since it is conceptually simple to reason about code when data cannot change right under your feet. However, I won't try to argue if this is actually the case or not, as this reply is already quite long as is. The point is that many concerns regarding immutable data structures are solved and functional languages also provide alternate paths when you need mutability.

Re: Comparing Elixir and Go

#85

Earlier quoted context omitted.

You only need to copy the data if the consumer of the data changes it, i.e. copy-on-write.

That sounds a bit better than I thought but it still doesn't change the worst-case complexity.

Consider a binary tree. You don't have to copy the whole tree, which is O(n) but rather only the "spine" path from the altered element to the top, which is O(lg n).

In practice, there are also many cases which ends up on the stack and never reaches the heap, so the memory allocation needs are somewhat smaller than what people think.

Another point is that short-lived garbage is collected in O(1) time in the GC. So you don't pay for its collection either. Things are slower than a mutation, but the overhead is lower than people tend to think.

Re: Comparing Elixir and Go

#86
post #40

This is more for people looking at erlang/elixir than a critique of the blogpost or a suggestion for a change. > 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 c…

This is a similar idea to a rope: https://en.wikipedia.org/wiki/Rope_(data_structure)

That's pretty much what iolists are, except you don't usually read iolists (or modify in ways other than concatenating) so you don't pay for that complexity cost. iolists are also mixed-type so you can have an iolist containing integers, strings and binaries (at the same nesting level or different ones) which means less transcoding pressure.

Re: Comparing Elixir and Go

#87

Author here. This was published a week earlier than expected so just a heads up that there are a couple of edits coming.

May I suggest some changes to the type parts:

* Elixir doesn't infer types. The language is dynamically typed, just as Erlang is. Using the word "inference" is somewhat dangerous since it means something very specific to a type theorist.

* Likewise, the compiler catches nothing, unless you are passing in a constant or literal. If you have `X Y` for arbitrary X and Y, the compiler can only catch it in statically typed languages (with or without type inference)

I think the main power of Elixir/Erlang compared to Go is the ability to handle arbitrary errors implicitly without the programmer having to write a single line of code. In Go, since there is a large shared heap, a goroutine must clean up after itself. In Erlang, memory is truly isolated, so a failing process can be cleaned up much like a traditional UNIX process can by the kernel. This creates system software far more robust.

Re: Comparing Elixir and Go

#88
If you want to really understand the philosophy that makes Erlang ( and Elixir ) beautiful ( and why it made me a better programmer ), this conference by Greg Young is a kind of eye opener : https://vimeo.com/108441214 .

You realize then that clustering, hot reload, availability etc... are not only features but the logical consequence of a beautifully crafted environnement that aims at developer productivity.

I'm sometimes amazed on how easy I can achieve stuff on the Erlang VM that would take ( if it's not impossible at all ) at least 10 times the time in a more usual language ( Ruby or PHP when you work in the web industry as I do ).

My last example was when I needed to batch sql inserts in an events database. In a normal language I would have needed a queue, the libraries for it, workers, new deployments and infrastructure to monitor, monitoring, supervision, etc... In Elixir, in 20 lines of code, it's done.

If you do not need complex calculations, the Erlang VM can basically become most of your architecture. It's already per se a SOA.

Re: Comparing Elixir and Go

#89

Earlier quoted context omitted.

But suitability is a huge factor here. The point isn't that "nine nines" reliability cannot be achieved in C++ or whatever, it's that it's significantly harder and costlier to achieve. But also: Of course a language creates reliability. Null pointers are impossible in Erlang, whereas they are provable impossible to avoid in C++. So people bring this up because Erlang programs are pretty much reliable by default (assu…

> Null pointers are impossible in Erlang, whereas they are provable impossible to avoid in C++. They are trivially possible to avoid in C++ as you do not have to use raw pointers. References, value types, custom non-null smart_ptrs, etc.

Don't underestimate the cost of trivial maintenance. In any project constrained by time, you risk people skipping on these things in part of the system. Erlang/Elixir is pretty well built for robustness, so a single library is less likely to affect the system as a whole. The same cannot be said for C++, where every part has to be close to correct for the operation to proceed as you expect.

The trade-off you get however, is that the explicit control in C++ tend to produce systems which run faster under nominal operation.

In practice, many Erlang systems contains some C/C++ parts at their core for fast operation. Depending on their complexity, you try to isolate them from the rest of the system as much as you can. In short, you use Erlang as a top-level control backplane for your C/C++ code. The advantage is you get the speed of C++ where needed, but the added productivity of Erlang everywhere else.

Erlang programmers are usually practically minded in this regard. "functional purity" doesn't really matter that much if the problem isn't solved.

Re: Comparing Elixir and Go

#90
post #61
post #58

Earlier quoted context omitted.

> 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. 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.

What is different in Erlang is that strings are a bit messed up in that they are linked lists of numbers. What you are suggesting (constructing the actual string in-place) works fine in Erlang, too, but has a bit of a funky syntax: welcome_user(Username) -> >/binary, Username/binary, >/binary >>. However, the main advantage of using io_lists instead is that `["Welcome", Username, "!"]` has constant complexity with re…

Note to anyone not already familiar: in Elixir, character strings are all binaries from the start. Just to avoid the notion that Elixir follows the mistake of strings-are-linked-lists from Erlang.
Post reply on HN