Hacker News new | ask | show | jobs
by behnamoh 483 days ago
Elixir has some features I wish Python had:

- atoms

- everything (or most things) is a macro, even def, etc.

- pipes |>, and no, I don't want to write a "pipe" class in Python to use it like pipe(foo, bar, ...). 90% of the |> power comes from its 'flow' programming style.

- true immutability

- true parallelism and concurrency thanks to the supervision trees

- hot code reloading (you recompile the app WHILE it's running)

- fault tolerance (again, thanks for supervision trees)

4 comments

Mix is also so much better than anything python has to offer in terms of build/dependency tooling.
uv for Python is a game changer, better than anything else out there and solves a lot of the core problems with pip/venv/poetry/pyenv (the list goes on).
I feel like you can write some variant of this comment every few years and just add the previous "best" to the front of the stack of things it's better than.
You're not wrong, this is the nth iteration of python tools that try to solve all the problems of what came before, including whatever the n-1th iteration introduced.

That said, in my personal experience with uv, it solves nearly all of the problems I've come across that were created by other python package management tools. It seems to have been very thoughtfully designed and I think there's a strong chance it'll become the standard, and that there won't need to be more standards after this. We'll see!

It’s true - people were saying that Poetry solves these problems for ages. Maybe uv does? I’ll wait and see.
This time they've got it for sure!
Jupyter might have fixed this now because it’s been a while since I used it, but Mix.install inline in Livebook (or any CLI script) is so much nicer than how installing Python dependencies in notebooks was last time I did that too.
Coming from Erlang, I think macros are one of the things I'm ambivalent about in Elixir. There are a bunch of actual improvements besides just the syntax itself in Elixir, like string handling, but things like macros in Ecto ... not yet a fan of that.
> ..but things like macros in Ecto....

Well, The whole language itself is built on macros. The following series of articles certainly helped me stop worrying and love the macros..

https://www.theerlangelist.com/article/macros_1

Some interesting insights from the article: "Elixir itself is heavily powered by macros. Many constructs, such as defmodule, def, if, unless, and even defmacro[1] are actually macros...."

[1] https://github.com/elixir-lang/elixir/blob/v1.18.2/lib/elixi...

In practice you don't really need to write macros if you don't make libraries.
You can abuse the '>>' notation in python for pipes (or you could use |, I suppose), but you'll have to deal with whitespace shenanigans. I'm also not entirely sure about the order of evaluation. And you'll need to do partial function application by hand if you want that (though it is possible to write a meta function for that).

So one could write

    class Piped:
        def __init__(self, value):
            self.value = value
    
        def __or__(self, func):
            return Piped(func(self.value))
    
        def __repr__(self):
            return f"Piped({self.value!r})"
    
    Piped('test') | str.upper | (lambda x: x.replace('T', 't')) | "prefix_".__add__ # => prefix_tESt
but whether that is a good idea is a whole different matter.
Apache Beam in Python does this, with code like

    counts = (
        lines
        | 'Split' >> (
            beam.FlatMap(
                lambda x: re.findall(r'[A-Za-z\']+', x)).with_output_types(str))
        | 'PairWithOne' >> beam.Map(lambda x: (x, 1))
        | 'GroupAndSum' >> beam.CombinePerKey(sum))

I'm not sure how I feel about it, other than the fact that I'd 100x rather write Beam pipelines in basically any other language. But that's about more than syntax.
The part of Elixir pipes that people overlook is the fact that, as a native, heavily used part of the language, the entirety of the standard library and most third party libraries are written with their behavior in mind. The first argument (the pipe target) will be the argument you want piped in faaaar more often than in languages where pipes are tacked on later.