Live data from Hacker News

Elixir 1.19

elixir-lang.org

71–80 of 152 posts

Re: Elixir 1.19

#71

Earlier quoted context omitted.

Gleam doesn't give you access to the full amazingness of OTP and BEAM. Elixir does.

Why? Don't they all compile down to the same AST? How does Gleam prevent the use of OTP? Honest question - not overly familiar with Gleam

No REPL for example.

Re: Elixir 1.19

#72

Elixir was not a happy experience. The language itself is maybe OK but the overall experience is not. On a production build, stack traces look like Erlang code, which is the weird syntax that Elixir tried to improve upon. Then you have macros, which make code unmaintainable at the 10k SLOC mark, and increasingly harder to maintain as projects get larger. Running "mix xref graph" on most Elixir projects shows a spaghe…

I'm sorry you had a bad experience, but this doesn't reflect the experience of most Elixir programmers. I'll share my experience as a counterpoint.

> On a production build, stack traces look like Erlang code...

Elixir has the most readable stacktraces of any language I've used. Here's an example (which is color-coded in the terminal for even more clarity and, as you can see, doesn't contain any Erlang code):

  == Compilation error in file lib/app_web/live/authentication/settings.ex ==
  ** (MismatchedDelimiterError) mismatched delimiter found on lib/app_web/live/authentication/settings.ex:96:1:
    error: unexpected reserved word: end
     │
   4 │   on_mount {AppWeb.UserAuth, :require_sudo_mode
     │            └ unclosed delimiter
  ...
   96 │ end
    │ └ mismatched closing delimiter (expected "}")
    │
    └─ lib/app_web/live/authentication/settings.ex:96:1
It's easy to see that the issue is on line 4, and that it is a missing curly brace.

> Then you have macros, which make code unmaintainable...

Elixir gives you full access to the AST, making macros extremely easy to read and reason through. The point of the Lisp-style macros Elixir uses is to simplify your code. If your code becomes unmaintainable due to your use of macros, you're probably misusing them. I'd have to see a sample to make that determination, though.

> Running "mix xref graph" on most Elixir projects shows a spaghetti mess.

Spaghetti? It's a simple two-level tree that is in alphabetical order. Here's an example, and it is like this all the way down:

  Compiling 26 files (.ex)
  Generated stow app
  lib/app.ex
  lib/app/accounts.ex
  ├── lib/app/accounts/user.ex (export)
  ├── lib/app/accounts/user_notifier.ex
  ├── lib/app/accounts/user_token.ex (export)
  └── lib/app/repo.ex
  ...
To me, this output seems extremely accessible.

> The toolchain has much room for improvement...

Having developed many Windows apps using Borland's tools in the 80s and 90s, I disagree with this statement for these reasons:

• Mix is one of the best and most integrated build tools/task runners I've used. For example, you can create, migrate, and reset databases, execute tests, lint code, generate projects, compile, build assets, install packages, pull dependencies, etc.

• ExUnit is a great testing framework that handles all kinds of tests in an easy-to-read DSL similar to Ruby's RSpec.

• IEx is a fantastic REPL.

• Elixir's debugging tools are excellent. For example, IEx.pry lets you stop all processes and interact with your system in that frozen state in the REPL. You can watch variables, run functions, and even create new functions on the fly to interact with your data to see how it behaves in different scenarios.

> Building a team around Elixir is hard.

Why is it hard? I've worked exclusively on Elixir projects for both start-ups and large companies with hundreds of engineers for over ten years now, and never had a problem with hiring teams.

> And the documentation for most of the projects you will use is full of noise, with few workable examples, grandiose claims of performance, and fantastic treasures, and the articles are a great read if you want to waste your entire evening.

All technical documentation could be improved, but Elixir's is already quite good. See for yourself: https://hexdocs.pm/elixir/1.19.0/Kernel.html.

Furthermore, from within IEx, you can type:

  function |> h
for any function and see an explanation of what the function does and examples of how to use it.

> Support for massive concurrency is nice, but you are realistically not going to need it...

Elixir supports minute concurrency as well, and yes, I do need it. For example, in Ruby on Rails, which has a GIL, I'd have to use a gem like Sidekiq to push long-running processes into Redis so they can be processed in the background. In Elixir, I can just run them in a separate, concurrent process, which is simple.

Here's an example that takes a collection of users and a function and then runs each user through that function, each in a separate thread:

  defmodule ParallelProcessing do
    def map(collection_of_users, func) do
      collection_of_users
      |> Enum.map(&(Task.async(fn -> func.(&1) end)))
      |> Enum.map(&Task.await/1)
    end
  end
Here's the same Elixir code running in a single thread.

  defmodule SequentialProcessing do
    def map(collection_of_users, func) do
      collection_of_users
      |> Enum.map(func)
    end
  end
In the first example, I could have 1 user, 1,000 users, or 1,000,000 users, and this code would run as optimally as possible on all the cores in my CPU or across all the cores in all the CPUs in my multi-server BEAM cluster. There are no extra programs or libraries needed. In the second example, users are processed one at a time, similar to languages like Python, Ruby, JavaScript, PHP, and Perl.

Given the simplicity of writing parallel code in Elixir, why would I limit myself to one CPU core to perform a task when I can use all cores simultaneously?

> Or deal with people that won't stop selling you how great the language is.

The reason they won't stop selling you on Elixir is that Elixir is a fantastic language. I hope you take the time to revisit it in the future. It really is much better than most things out there.

Re: Elixir 1.19

#73
post #68

Earlier quoted context omitted.

Scala 3 has failed to be widely adopted, and now the language as a whole is more or less dead. Not that that’s due to the 2-to-3 transition entirely.

I haven't been following, now I'm sad to hear... Scala is really dead? What'd be the JVM alternative?

Don't know about Scala alternative, but the language I've found most enjoyable on the JVM is definitely Kotlin.

Re: Elixir 1.19

#74
post #39

Earlier quoted context omitted.

> So many examples of programming languages have huge breaking changes between versions I can only think of 2: python 3 and perl 6. Those two were very traumatic so it's not surprising it feels like more.

Although it was somewhat optional, adding async to Rust had a similar feel. Also various Swift versions had source breaking changes back in the day.

I gave up on Swift when the next release suddenly required actor annotations all over the place. They've been making weird decisions lately.

Re: Elixir 1.19

#75
post #2

The progressive introduction of automated type checking in Elixir should serve as a reference on how to improve a programming language gracefully without breaking changes. So many examples of programming languages have huge breaking changes between versions that end up creating a split in the ecosystem that takes years to resolve. Thankfully José has been very clear about Elixir being done since at least 2018. The la…

> So many examples of programming languages have huge breaking changes between versions I can only think of 2: python 3 and perl 6. Those two were very traumatic so it's not surprising it feels like more.

NodeJS with its commonjs vs modules, it's a huge mess IMO. Add typescript and build systems for bonus clusterf*cks.

Re: Elixir 1.19

#76
post #57

Earlier quoted context omitted.

> So many examples of programming languages have huge breaking changes between versions I can only think of 2: python 3 and perl 6. Those two were very traumatic so it's not surprising it feels like more.

.NET Framework => .NET While C#, F#, VB and C++/CLI were kept compatible, it doesn't help when the library stuff you want to call isnt' there any longer. C++ removal of exception specifiers, GC API, C VLAs got dropped in C11, function prototypes changed meaning in C23, and K&R declarations were dropped from the standard. Java, already someone else mentioned. D, the whole D1 => D2 transition, and Tango vs Phobos drama…

> GC API,

Bit of a quibble but I'm not sure I'd call that a "huge breaking change" given that that feature wasn't really implemented in the first place, let alone actually used.

Re: Elixir 1.19

#77

Earlier quoted context omitted.

> So many examples of programming languages have huge breaking changes between versions I can only think of 2: python 3 and perl 6. Those two were very traumatic so it's not surprising it feels like more.

Scala 3 has failed to be widely adopted, and now the language as a whole is more or less dead. Not that that’s due to the 2-to-3 transition entirely.

That happens to all guest languages unless that have unique selling points that make that differention happen and take off on their own, as genesis for their own platform.

See all platforms that have their identity tied with a specific language, the platform's language always has a guaranteed future as long as the platform continues to be industry relevant.

The others on top, come and go.

Re: Elixir 1.19

#78
post #22

Earlier quoted context omitted.

> So many examples of programming languages have huge breaking changes between versions I can only think of 2: python 3 and perl 6. Those two were very traumatic so it's not surprising it feels like more.

C++11 fucking with strings also comes to mind.

That was more a GCC problem, but yeah.

Re: Elixir 1.19

#79
post #66
post #10

Just a data point on the deps compilation, on a small Phoenix app with mostly stock Phoenix deps: MIX_OS_DEPS_COMPILE_PARTITION_COUNT=1 mix deps.compile 32.30s user 7.23s system 320% cpu 12.336 total MIX_OS_DEPS_COMPILE_PARTITION_COUNT=5 mix deps.compile 0.37s user 0.49s system 12% cpu 6.970 total MIX_OS_DEPS_COMPILE_PARTITION_COUNT=10 mix deps.compile 0.38s user 0.50s system 12% cpu 7.236 total Machine is a Mac M1 M…

You're measuring a cached compile in the subsequent runs. The deps.compile probably did some native compilation in the dep folder directly rather in _build.

No their results are correct. It roughly halved the compilation time on a newly generated Phoenix project. I'm assuming the savings would be more extensive on projects with multiple native dependencies that have lengthy compilation.

    rm -rf _build/ deps/ && mix deps.get && time MIX_OS_DEPS_COMPILE_PARTITION_COUNT=1 mix deps.compile
    ________________________________________________________
    Executed in   37.75 secs    fish           external
       usr time  103.65 secs   32.00 micros  103.65 secs
       sys time   20.14 secs  999.00 micros   20.14 secs

    rm -rf _build/ deps/ && mix deps.get && time MIX_OS_DEPS_COMPILE_PARTITION_COUNT=5 mix deps.compile
    ________________________________________________________
    Executed in   16.71 secs    fish           external
       usr time    2.39 secs    0.05 millis    2.39 secs
       sys time    0.87 secs    1.01 millis    0.87 secs
    
    rm -rf _build/ deps/ && mix deps.get && time MIX_OS_DEPS_COMPILE_PARTITION_COUNT=10 mix deps.compile
    ________________________________________________________
    Executed in   17.19 secs    fish           external
       usr time    2.41 secs    1.09 millis    2.40 secs
       sys time    0.89 secs    0.04 millis    0.89 secs

Re: Elixir 1.19

#80

Elixir is still confusing, not the language, but the ecosystem, tooling, and philosophy. Is it dynamic or static? Is it compiled or not? If it's not, then why do we have Elixir scripts, which have different file extension? If it uses BEAM and you'd inevitably need to know Erlang when you hit the edge cases, then why not just learn Erlang? If it solves concurrency the "right way" due to supervision trees, why not use…

Python has a GIL and is mutable, which makes concurrency impossible and error-prone, respectively. Elixir doesn't have a GIL and is immutable.

Not really.

CPython used to have a GIL, it is no longer the case since the latest version, 3.14.

Other Pythons, jPython, GrallPy, PyPy, never had a GIL.

Languages and implementations aren't the same.

Post reply on HN