[HN Gopher] Elixir for cynical curmudgeons
       ___________________________________________________________________
        
       Elixir for cynical curmudgeons
        
       Author : todsacerdoti
       Score  : 337 points
       Date   : 2023-08-03 14:51 UTC (8 hours ago)
        
 (HTM) web link (wiki.alopex.li)
 (TXT) w3m dump (wiki.alopex.li)
        
       | golemotron wrote:
       | Disappointed. I thought it was going to describe a way for
       | cynical curmudgeons to get out of their rut.
        
       | simmanian wrote:
       | If I volunteer at a nonprofit and I'm trying to run a team of
       | volunteers who would...                 1) probably not stick
       | around for long       2) need to be trained from scratch       3)
       | not have a solid development background
       | 
       | Would Phoenix be a good choice, given that you can do so much
       | with it without needing to learn many other tools, or would it be
       | better to start with something like Supabase + a javascript front
       | end framework and hope we'll never have to deal with monsters
       | like kubernetes?
        
         | biorach wrote:
         | phoenix does not sound like a good fit
        
         | impulser_ wrote:
         | I would probably go with Javascript and Supabase, this would
         | require you to only really worry about the frontend. Javascript
         | is also probably easier to train people because of how many
         | resources there are out there about training people to write
         | Javascript. Supabase is also has a great free tier which will
         | help your nonprofit. Hell, you might even want to try to
         | contact them and they might give you a better tier for free
         | they are really friendly there.
         | 
         | Elixir is great, and developers love it but training new people
         | without a solid development background might be hard.
        
       | Dowwie wrote:
       | Things I like about Elixir:
       | 
       | - concurrency is intuitive!
       | 
       | - Elixir is a two-for-one language. You can reach into Erlang std
       | library as easily as you can that of Elixir. So, depending on
       | your work, you get a chance to discover a wide range of goodies
       | that come for "free". Examples include gen_tcp, gb_tree, etc.
       | 
       | - You can remote into a running virtual machine in production,
       | pod or whatever, and have access to a repl that let's you inspect
       | state, manage "processes", and manually invoke commands to
       | troubleshoot issues. The observer, and tui counterpart, are quite
       | useful too.
       | 
       | - everyone in the community writing libraries uses the standard
       | approach to emitting telemetry, saving time and effort for users
       | to take what is available
       | 
       | - fast compile times
       | 
       | - hardest working BDFL (although this presents risks, too), who
       | also has a pleasant, respectful disposition
       | 
       | - the community is respectful
       | 
       | Things I don't like:
       | 
       | - dynamic language leads to pattern matching or type mismatch
       | errors at runtime that could have been caught at compile time
       | 
       | - Elixir Phoenix doesn't have a large community, nor much up to
       | date reference material, or literature. If you're not experienced
       | with Front-end dev, it's easier to onboard with a modern SPA
       | framework like React.
       | 
       | - supply of Elixir talent exceeds demand, although this isn't
       | unique to Elixir (e.g Rust)
       | 
       | - slowly growing ecosystem, relatively speaking
        
         | melvinroest wrote:
         | The changing code in production with a REPL reminds me of
         | Pharo. Though, with Pharo you get a whole IDE :D
         | 
         | I also feel that Pharo has too small if a community. The ESUG
         | conference is coming up soon though. It's good to see they're
         | coming together
         | 
         | Why is concurrency intuitive?
        
           | Dowwie wrote:
           | There's no function color. The concurrency patterns are well
           | defined, documented and discussed. You don't need to sit in a
           | chat room asking for help from a benevolent core team of
           | maintainers.
           | 
           | Granted, I did learn the hard way about introducing cycles
           | but the error messaging lead me to the root of the problem
           | quickly.
        
         | jpbastyr wrote:
         | If you're a fan of the ecosystem, but not of dynamic types,
         | there are statically typed languages on BEAM, eg Gleam
         | (https://gleam.run/)
        
         | beeburrt wrote:
         | > supply of Elixir talent exceeds demand, although this isn't
         | unique to Elixir (e.g Rust)
         | 
         | Is this true?
        
           | sarchertech wrote:
           | At my current company we've many times had to hire and train
           | people who had no elixir experience. If anything I'd say the
           | demand for experienced people exceeds supply.
        
             | esclerofilo wrote:
             | Talent and experience are not the same thing, and I would
             | say experience is a lot more correlated to demand of talent
             | than to supply of it. More demand means more opportunities
             | to get experience.
        
           | Dowwie wrote:
           | No, I am lying. The most jobs out there are for elixir
           | engineers and managers are struggling to fill vacancies.
        
             | RadiozRadioz wrote:
             | Why be so unnecessarily subversive?
        
         | OkayPhysicist wrote:
         | What the documentation for Elixir and its big libraries (Ecto
         | and Phoenix) lack in quantity of documentation, they
         | exceedingly make up for in quality of documentation. Who needs
         | a bunch of garbage blog posts about how to do xyz, when the
         | official docs painstakingly lay out not only what you need to
         | know, but also present it in a readable and discoverable way?
        
       | bhaney wrote:
       | > `if` is a macro.
       | 
       | > `def` is a macro.
       | 
       | > `defmodule` is a macro.
       | 
       | > It's all macros. It's ALL MACROS! ALL THE WAY DOWN! AAAAAAAAAA
       | AHAHAHAHAHHAHAAAA!
       | 
       | Also see the definition for `defmacro`, the macro for defining
       | macros, which is defined using... defmacro
       | 
       | https://github.com/elixir-lang/elixir/blob/v1.15/lib/elixir/...
        
       | plainOldText wrote:
       | The syntactic sugar for the list of tuples (aka the _Keyword
       | list_ ), such as: _[one: 1, two: 2]_ instead of _[{:one, 1},
       | {:two, 2}]_ and the other _... do:_ macros drove me crazy when I
       | first learned Elixir. But as soon as I familiarized myself with
       | it and a few other gotchas, Elixir managed to become my favorite
       | and main language.
        
       | aeturnum wrote:
       | Always glad to see another person finding their way to Elixir!
       | 
       | IMO the biggest tripping point for people (including, clearly,
       | this author) is the freedom. They said that the "Big complicated
       | project structure" was a stumbling point - but there is no
       | structure! You can actually do it any way you want. But there are
       | _conventions_. Mix suggests that you lay our your project in a
       | certain way (and most Elixir projects are laid out that way) -
       | but you are not required to by the language.
       | 
       | Nearly everything in the language is a convention (including the
       | test / dev / prod run modes). This applies to Erlang as well. It
       | has standard approaches, but you don't /have/ to follow them. I
       | frequently get confused about the way libraries tend to approach
       | something (do you have to do it this way? Is there a
       | requirement?) and the answer is generally "no, but the community
       | tends to think this is the best way to do it and so people
       | generally do it this way."
       | 
       | A great example of everything being a convention: structures
       | aren't a language feature. They're maps with special keys and
       | Elixir library support. The upside and downside to this is that
       | you could actually do almost anything with them - if you have the
       | time and the skill to implement the system. MANY things are like
       | this when you get into it.
        
       | ljm wrote:
       | I'm really enjoying getting to grips with Elixir, but I'm still
       | really in two minds about Ecto having a macro-based SQL ORM.
       | 
       | Like any ORM, the abstraction leaks, but it really throws you off
       | course when you're trying to map the host syntax to raw SQL.
       | from(t as SomeTable, where: x.z == ^y, join: x on assoc(t, :y))
       | 
       | Like, it's macro enough to make SQL feel more first-class...but
       | not enough to actually make it first class, so you've gotta learn
       | Ecto's quirks.
       | 
       | It's also chainable so it's a macro over a query builder that
       | eventually resolves to SQL at runtime.
        
       | LispSporks22 wrote:
       | Lisp user here. I couldn't see what he was talking about re:
       | "Elixir is a Lisp" and the "why" was pretty hand-wavy, but the
       | author does seem pretty stoked about whatever he/she saw so good
       | for them.
        
         | weatherlight wrote:
         | hygienic macros doe not make a lisp, but.... it get you very
         | close to the spirit of the thing, i think that's why the author
         | was excited,( and it's a good reason to be.)
        
       | BaculumMeumEst wrote:
       | elixir seems cool and i love its tooling but the more i use
       | datomic, the less i want to spend my time dealing with SQL and
       | its baggage unless i absolutely have to.
        
         | whalesalad wrote:
         | what would prevent you from using datomic with elixir?
         | https://github.com/edubkendo/datomex
         | 
         | there are other datalog-y tools as well, ie
         | https://github.com/naomijub/translixir
        
           | BaculumMeumEst wrote:
           | i lost my enthusiasm for building a jenga tower of niche
           | community libraries
        
             | whalesalad wrote:
             | that is literally clojure development
        
               | BaculumMeumEst wrote:
               | you can get pretty far with cognitect's libraries and
               | java interop
        
       | rekoros wrote:
       | I usually just blindly upvote anything with Erlang/Elixir in the
       | title, but this one I read in its entirety over some Pho
       | 
       | Excellent writeup!
        
       | dgb23 wrote:
       | > the harder something tries to convince me of anything, the more
       | I expect it to suck.
       | 
       | That's me vs web development in general and especially in the JS
       | ecosystem. Other, similar red-flags: hand holding, "best
       | practices", "anti-patterns" and other voodoo and cargo culting.
       | 
       | The most suspicious one is prettiness:
       | 
       | - custom DSL syntax without data representation
       | 
       | - cosmetic wrappers that are just thin layers without substance
       | 
       | - "everything is an X" for the sake of faux consistency
        
         | throwawaymaths wrote:
         | - cosmetic wrappers that are just thin layers without substance
         | 
         | If you've ever tried to write keyword lists in erlang.... The
         | keyword list cosmetic wrapper is fucking amazing, not only
         | because it makes it easy to read, but it makes it easier to
         | debug and easier to one-glance see "this is a keyword list".
        
         | 59nadir wrote:
         | > - custom DSL syntax without data representation
         | 
         | This is an interesting comment in a post about Elixir because
         | the Elixir ecosystem is actually full of things that should
         | just be data but are instead macros being used in modules.
         | Phoenix in particular is an especially egregious example of a
         | library that is badly made in almost every regard
         | 
         | > - cosmetic wrappers that are just thin layers without
         | substance
         | 
         | This one is also funny because Elixir itself is little more
         | than a fairly small set of convenience libraries, a syntax and
         | a very good tool for project management (`mix`) on top of
         | Erlang. You can skip the syntax and the convenience libraries
         | for the most part and actually just use Erlang in a `mix`
         | project and get the best of both worlds. The convenience
         | libraries usually are bad makeup on top of Erlang in many cases
         | and you'd be better served just learning the Erlang way anyway.
        
           | jeremyjh wrote:
           | Phoenix is popular partly because people like its API and its
           | convenience macros. It won out over Jose's own framework,
           | Dynamo which he scrapped in favor of becoming a core
           | contributor to Phoenix. Its easy to make yourself sound wise
           | by complaining about macros, but this largely boils down to
           | personal preferences, and a lot of people have different ones
           | from you.
           | 
           | For most of the people who actually use Phoenix, the DSL
           | makes intuitive sense and so there isn't much learning curve,
           | and it is such an important library to applications that use
           | it that its worth taking the time to really learn it, whereas
           | it might not be the case for other libraries that are macro
           | heavy. Most libraries don't go that route though.
        
           | arrowsmith wrote:
           | > Phoenix in particular is an especially egregious example of
           | a library that is badly made in almost every regard
           | 
           | Can you elaborate on this? Why do you think this?
        
             | 59nadir wrote:
             | The interface to almost everything either contains or is
             | based on a macro. This persists even in cases where you can
             | clearly see there needed to be no macros at all.
             | 
             | The non-standard (won't work with anything else) and
             | basically superfluous websocket protocol has bad
             | fundamentals and has been marred by bad JavaScript code
             | being needed for it. On top of that it's pretty bloated.
             | 
             | The actual channel processes could've simply followed a
             | standard Erlang interface but someone (...) felt they
             | needed to put their fingerprint on it, I guess, so it kind
             | of doesn't. And yes, again everything surrounding channels
             | is a bunch of macros until you at least get to write and
             | use normal functions in the actual channel module.
             | 
             | They've had a long history of arbitrarily deciding to hide
             | settings/configuration from dependencies they use and
             | having no actual argument for doing so when asked to expose
             | them.
             | 
             | If the part about macros being overused wasn't bad enough
             | Phoenix also promotes this type of thinking by overusing
             | them even in generated code, so people can follow the bad
             | example.
        
               | josevalim wrote:
               | > The interface to almost everything either contains or
               | is based on a macro.
               | 
               | This is not true. The endpoint and router are macro
               | based, but once it is routed, it is all functions. Your
               | controller actions are functions, calling the
               | view/template is a function, your channel is functions,
               | the model/context layer are functions.
               | 
               | When it comes to behaviors, we do our best to follow
               | Erlang/OTP conventions, but deviate where it makes sense.
               | For example, channel has "join" instead of "init" because
               | you can refuse a join but you can't refuse an init. They
               | have different return types and augmenting init could be
               | confusing if later you were to write a plain GenServer.
               | 
               | It is easy to look from outside and say "someone wanted
               | to put their fingerprints on it" but actual discussions
               | were had in pretty much all of these topics. I suggest
               | asking around. If you asked for something and we had no
               | actual arguments, then please point me to such
               | occurrences. I will be eager to clarify (and as a rule we
               | generally do).
        
           | giraffe_lady wrote:
           | I know erlang better than I know elixir but I still prefer to
           | use elixir when I have the choice.
           | 
           | It may be "little more than" convenience, but especially
           | consistency decisions like always data-first functions plus
           | the pipe macro is already a monumental ergonomic leap over
           | erlang. I love erlang but, like php, it is a language where I
           | have to look up the argument order and config options of
           | every function every time I use it.
        
       | throwawaymaths wrote:
       | Yep. The only problem with elixir macros is that people look at
       | the macros that are in core++ (exunit, plug, phoenix, ecto) and
       | decide it's a good idea to dsl-up everything.
       | 
       | The biggest offenders IMO are commanded, Tesla, absinthe,
       | exmachina and now most recently ash. Then there's tons of tiny
       | libraries that litter hex.pm with macro-heavy nonsense.
       | 
       | At least the core++ libraries make macros whose syntax/keywords
       | matches something _outside_ elixirland that you 'd have to know
       | anyways (e.g. 'get' from plug, all of SQL from ecto), but the big
       | offenders list are making up clever names for things, which adds
       | mental overhead to literally everything you do, building crazy
       | complicated compilation pathways (especially for overeagerly lazy
       | stuff) or writing function names from whole cloth that make
       | refactoring or searching your codebase a nightmare (or more than
       | one). E.g. if you're working in a domain where non-proud camel
       | case is the convention, don't automatically snake-case it.
        
         | bmitc wrote:
         | As someone who loves Elixir and knows it, this is one thing
         | that really makes it hard to learn Phoenix for me personally. I
         | have struggled learning Phoenix because it is so heavy with
         | macro upon macro that it feels like learning another language.
        
           | throwawaymaths wrote:
           | I have some bad news for you: elixir ecosystem is
           | consultancy-driven ecosystem. While at least better than
           | bigtech-driven ecosystem (cough cough), the changes you seek
           | are less likely to happen because
           | 
           | 1. They make it easier for consultancies to templatize what
           | they do, which:
           | 
           | - keeps their employees tied to the hard earned knowledge
           | 
           | - keeps their clients tied to their services
           | 
           | At least though you know that those patterns are (usually)
           | common and battle tested (or, at least, will be battle tested
           | - cough cough ash), and unlike a bigtech "their problems are
           | likely to be your problems".
        
             | josevalim wrote:
             | > - keeps their clients tied to their services
             | 
             | I have heard this claim so many times but it is easy to
             | prove it wrong given how much we focus on documentation and
             | understandability around Elixir and main libs. I have had
             | clients asking me questions and I would answer it by
             | improving the docs or writing a guide, committing it to the
             | repo, and then asking the client for feedback. Half of the
             | Ecto guides were written like this.
             | 
             | It is not about keeping clients at all. It is about having
             | a great on-boarding (and beyond) experience.
        
             | nkjnlknlk wrote:
             | is the claim Ash is not battle tested?
        
         | halostatue wrote:
         | I haven't used commanded, exmachina, or ash:
         | 
         | - Tesla has a mode which can be used completely without macros,
         | and I am increasingly encouraging that it be the only way that
         | it is used. So does the author (as of 2020):
         | https://github.com/elixir-tesla/tesla/issues/367#issuecommen...
         | 
         | There is also `req` mentioned in a recent post as an
         | alternative (it looks good, but I am still playing with it to
         | see if it is a suitable replacement for Tesla in all cases).
         | 
         | - Absinthe is something of a compiler itself, because it has to
         | _strictly_ define things the way that is specified in the
         | GraphQL spec. You can now import an SDL file, but you still
         | need to hook resolvers and middleware into it. Honestly, I
         | don't think that the schema definitions in JS /TS are much
         | better for GraphQL in terms of readability.
         | 
         | Being heavily macro-based means that there are sharp edges that
         | are harder to work around when you want to add your own macros
         | for code reuse purposes. That said, aside from the _schema_
         | definition, Absinthe is entirely usable _without_ macros.
         | Within the schema definition, Absinthe isn't making anything
         | up, it's using the same basic definitions that the GraphQL spec
         | do, adapted for Elixir syntax.
         | 
         | Exmachina didn't interest me because I don't think much of
         | factory_bot (which used to be called factory_girl), as I saw it
         | abused far more than used well (IMO, it's impossible to use
         | correctly). Ash...looks like an interesting experiment, but I
         | don't know that there's a lot of pick-up with it compared to
         | Phoenix. And I have yet to find a use for CQRS/ES, so there's
         | no reason for me to play with commanded. I certainly wouldn't
         | consider any of these three to be "major" players in Elixir.
         | Tesla and Absinthe? Yes.
        
         | freedomben wrote:
         | Yep this is definitely a problem, but fortunately the
         | culture/community around Elixir generally tends to frown on
         | unnecessary macros. I heard the saying, "if it can be a normal
         | function, it should be" many times, which pleases me.
         | 
         | Overall though this isn't something I've generally run into too
         | much with Elixir.
        
           | throwawaymaths wrote:
           | Mark my prediction: as the big "non-core++" libraries get
           | bigger and trashier with their macros, and more used by the
           | community, hex.pm will become littered with even more trashy
           | macro libraries, and people will stop saying "don't use
           | macros".
        
             | johnisgood wrote:
             | I'm sleep deprived. Would not it rather be "start" saying
             | "don't use macros", given that macros are "bad"?
        
             | cschmatzler wrote:
             | I'm pretty sure that the libraries you consider core++ such
             | as ExUnit and Ecto are considered feature complete and
             | won't get any bigger.
        
               | throwawaymaths wrote:
               | Correct, but remember core++ seeded atrocities like
               | ExUnit.CaseTemplate.
               | 
               | Anyways my prediction is about Non-core++ libs, which I
               | listed in gp.
        
               | josevalim wrote:
               | I was never fully pleased with ExUnit.CaseTemplate. If
               | you have suggestions I am all ears. :)
        
           | 59nadir wrote:
           | > Yep this is definitely a problem, but fortunately the
           | culture/community around Elixir generally tends to frown on
           | unnecessary macros. I heard the saying, "if it can be a
           | normal function, it should be" many times, which pleases me.
           | 
           | While Elixir people usually say this, they don't at all
           | follow it in practice because of the terrible example set by
           | all the libraries. Phoenix is especially egregious and I
           | can't believe the grandparent didn't bring it up.
           | 
           | Looking at Clojure's solution that is (as far as I can see)
           | very popular it makes me annoyed at the relaxed attitude
           | towards macros in Elixir and how bad it actually is:
           | 
           | Elixir and `Plug.Router`:                   defmodule
           | MyRouter do           use Plug.Router                    plug
           | :match           plug :dispatch                    get
           | "/hello" do             send_resp(conn, 200, "world")
           | end                    forward "/users", to: UsersRouter
           | match _ do             send_resp(conn, 404, "oops")
           | end         end
           | 
           | Clojure and `reitit` (https://github.com/metosin/reitit):
           | (def router           (r/routes             [["/hello" {:get
           | (fn [r] {:status 200 :body "world"})}]              ["/users"
           | {:name :users                         :router users-router}]
           | ["*" {:get (fn [r] {:status 404 :body "oops"})}]]))
           | 
           | basically everything in the Elixir case is a macro and non-
           | standard syntax whereas literally of the components of the
           | Clojure case are just standard data types, and yet it manages
           | to be more readable.
        
             | no_wizard wrote:
             | `conn` is a magic argument isn't it? Like an implicit
             | argument to this block of code?
             | 
             | That is one thing that really bugs me, is I can't
             | automatically see where the arguments are coming from. I
             | realize it makes code a little more verbose, but a
             | requirement around explicitly showing the dependencies used
             | is much more useful when you're refactoring, for instance,
             | or scaling code.
             | 
             | not a hard requirement by any means, sure, and it
             | definitely doesn't mean something won't scale as it were,
             | however I am constantly frustrated by languages that allow
             | for implicit scoped dependencies / arguments.
        
               | halostatue wrote:
               | Yes, it's a bit of a magic argument, but it's the only
               | unhygienic variable introduced with a Plug dispatch:
               | 
               | https://github.com/elixir-
               | plug/plug/blob/main/lib/plug/route...
               | 
               | Everything else is explicitly passed, AFAICT.
        
             | arrowsmith wrote:
             | Maybe it's just down to familiarity, but I find the Phoenix
             | example more readable than the Clojure one. To each their
             | own I guess.
        
               | [deleted]
        
             | throwawaymaths wrote:
             | Actually I think plug is mostly fine since it only brings
             | in one macro (plug) that isn't an http verb, or http common
             | concept (forward e.g.).
             | 
             | My huge beef with plug is that it creates an implicit conn
             | variable in all of the plug bodies.
             | 
             | But yeah, phoenix is a combination of good choices and some
             | real stinkers, and I did mention it.
             | 
             | Edit: I forgot about match. match "isn't great".
        
               | dqv wrote:
               | >My huge beef with plug is that it creates an implicit
               | conn variable in all of the plug bodies.
               | 
               | What do you mean? That only happens if you use
               | Plug.Router; otherwise, you have to define a call
               | function that takes the conn as the first argument. You
               | can even go as far as explicitly calling the init
               | functions for each Plug manually. It's init(opts),
               | call(conn, opts) all the way down.
        
             | dragonwriter wrote:
             | > basically everything in the Elixir case is a macro and
             | non-standard syntax whereas literally of the components of
             | the Clojure case are just standard data types, and yet it
             | manages to be more readable.
             | 
             | "Readable" is mostly a matter of "fits the grooves already
             | worn in my brain"; to me, the Elixir there nonstandard-
             | macro-based-syntax-and-all, is _vastly_ more readable than
             | the Clojure.
        
               | 59nadir wrote:
               | > "Readable" is mostly a matter of "fits the grooves
               | already worn in my brain"; to me, the Elixir there
               | nonstandard-macro-based-syntax-and-all, is vastly more
               | readable than the Clojure.
               | 
               | I'll admit to being able to read Lisp syntax without
               | choking on the parens, but I don't even use Clojure (or
               | any other dialect that uses special syntax for the
               | different collection types) and I think it's way more
               | readable and malleable (you can literally do whatever you
               | want that makes sense to this data and it'll work,
               | meaning you're free to write whatever middleware you want
               | that takes and produces the expected data).
               | 
               | I've used Elixir since 2015 so I have no problem actually
               | reading the syntax at all; I just think it's factually
               | much worse than the Clojure example because it's
               | basically just a bunch of macros you can't do much with
               | and lots of implicit behaviors.
               | 
               | This also applies to Elixir's greater position in the
               | BEAM ecosystem. I think the idea was that Elixir was
               | going to be a boon to Erlang and other languages in there
               | over time but I think it's demonstrably pretty useless as
               | a BEAM citizen except for some of the patches they've
               | submitted; most big Elixir libraries can't even be used
               | outside of Elixir because they're full of macros and
               | don't even provide interfaces with just functions.
        
               | hosh wrote:
               | Sure. But there were improvements to the ecosystem.
               | Telemetry is a great example, though they ended up
               | porting it to Erlang so that both Erlang and Elixir
               | projects can use it.
        
               | josevalim wrote:
               | > I think the idea was that Elixir was going to be a boon
               | to Erlang and other languages in there over time but I
               | think it's demonstrably pretty useless as a BEAM citizen
               | except for some of the patches they've submitted
               | 
               | Not sure whose idea it was but I would say this is a very
               | inaccurate take. Of course, we have taken much more from
               | Erlang than given (that's expected from hosted
               | languages), but I personally sit on more than 100 PRs to
               | Erlang/OTP. I made binary matching several times faster
               | by using SIMD. I improved the compiler performance
               | (including Erlang programs) by (conservatively) 10-20%. I
               | contributed compiler optimizations to reduce memory
               | allocation. There is a now faster sets implementation
               | which I contributed. Erlang/OTP 26 ships with faster map
               | lookups for atom keys based on a pull request I
               | submitted. The new logger system in Erlang takes ideas
               | from Elixir logger. The utf-8 string handling in Erlang
               | is based wholesale on Elixir's (and extended for lists).
               | And this is in no way a comprehensive listing [1].
               | 
               | And this is not counting everyone else in the Elixir
               | community who contributed and those who are now actively
               | working on Erlang tooling and were on-boarded to the
               | ecosystem via Elixir. The Erlang ecosystem now has a
               | package manager [2], used extensively by both languages,
               | rebar3 and Mix, all implemented and powered by Elixir.
               | 
               | And then there are efforts like the Erlang Ecosystem
               | Foundation, which is made of developers and sponsored by
               | companies working with both languages, and it delivers
               | important projects around observability, documentation,
               | and more. For example, you can find several Erlang
               | projects now using ExDoc for documentation, such as Recon
               | [3].
               | 
               | That's my take. What are your demonstrations that we are
               | pretty useless for the BEAM ecosystem?
               | 
               | 1: https://github.com/erlang/otp/pulls?q=is%3Apr+author%3
               | Ajosev... 2: https://hex.pm/ 3: https://hexdocs.pm/recon
        
               | troupo wrote:
               | Elixir was the kick that Erlang needed for a long time.
        
               | josevalim wrote:
               | Honestly, I don't care if we were a kick or not :) but
               | saying we are "demonstrably pretty useless" is completely
               | unfair and bordering on being a bad faith argument.
        
           | hosh wrote:
           | Not to mention that the macros should be invoking regular
           | functions, making it easy to skip macros if you so choose.
           | 
           | When I pivoted from Ruby to Elixir, I was expecting to do a
           | lot more metaprogramming, but I found that regular functions
           | with pattern matching already does a lot that I want for many
           | cases.
        
         | sodapopcan wrote:
         | I personally don't have any problem with heavy macro-use in
         | libraries, I feel like that is where they shine. So long as the
         | documentation is good, I don't really care how the library
         | itself is implemented. I would much rather have the cleaner API
         | in many cases. I know it can be taken too far, though. Some
         | funky stuff can happen in Phoenix's router, though a lot of it
         | is actually to reduce cyclic compile-time dependencies as the
         | router is a place where these necessarily happen.
         | 
         | Macros in business code, however, are pure evil. I feel like
         | anyone who spent any time in Rails over the past decade has
         | learned that lesson.
        
           | throwawaymaths wrote:
           | Yep. I wish `pipeline`, `scope` and `resources` in Phoenix
           | router and also all the `use MyApp.Web, :x`, would just die
           | in a fire.
           | 
           | Thank goodness they got rid of views though I still am
           | annoyed that the default path resolution on templated content
           | isn't explicit.
           | 
           | The crazy thing is that the most amazing part of phoenix,
           | liveview, is almost no macros.
        
             | arrowsmith wrote:
             | > I wish `pipeline`, `scope` and `resources` in Phoenix
             | router and also all the `use MyApp.Web, :x`, would just die
             | in a fire.
             | 
             | How would you prefer it worked/looked?
             | 
             | > I still am annoyed that the default path resolution on
             | templated content isn't explicit.
             | 
             | What do you mean by this? In the new 1.7 approach to views,
             | you explicitly set the path in each view using
             | `embed_templates` (if you're not defining your HEex
             | directly within the view module itself.) What part isn't
             | explicit?
        
               | throwawaymaths wrote:
               | > What do you mean by this? In the new 1.7 approach to
               | views, you explicitly set the path
               | 
               | For example, if you wrote a liveview called FooView in
               | /path/to/my_liveview, a default render() will look for
               | /path/to/my_liveview/foo_view.html.heex
               | 
               | (Also note auto-snakecasing)
               | 
               | Btw, this is still a different semantic if you do the
               | deadview equivalent, which will try to do a path
               | resolution in /templates.
               | 
               | I guess these are minor complaints but I would much
               | prefer they use the same default strategy and, say, pass
               | the path in `use Phoenix.Liveview`
        
               | arrowsmith wrote:
               | > This is still a different semantic if you do the
               | deadview equivalent, which will try to do a path
               | resolution in /templates.
               | 
               | Not true in 1.7 - views* don't have any kind of "default"
               | template resolution; you have to explicitly state the
               | template path with `embed_templates`. That is if you're
               | not just defining your HEEx directly within the view
               | module itself, as I already mentioned.
               | 
               | *By "views" I mean the new style that uses `use MyAppWeb,
               | :html`, not the old style you describe which is now (in
               | 1.7+) only available as the external dependency
               | `phoenix_view`. The new style of module is still called a
               | "view" by the docs:
               | https://hexdocs.pm/phoenix/request_lifecycle.html#from-
               | endpo...
        
             | sodapopcan wrote:
             | I never use `resources` though have no beef with `pipeline`
             | or `scope`, though I haven't thought too much about it. It
             | is a little weird getting used to which modules are getting
             | auto-qualified and which aren't, but I'm long passed that.
             | And that is actually what is "fixing" the cyclical
             | dependency issue.
             | 
             | What's wrong with the `use MyApp.Web, :x`? You can easily
             | get rid of it as it's just generated boilerplate. It's a
             | nice little pattern to allow all the different things to
             | share the view helpers. If you'd like to be extra explicit,
             | though, just delete the file and include everything
             | manually.
             | 
             | I'm indifferent on views because I never really used them,
             | haha.
        
               | halostatue wrote:
               | I personally would prefer something like:
               | defmodule MyApp.Web.Router do           use MyApp.Router
               | end
               | 
               | over                   defmodule MyApp.Web.Router do
               | use MyApp, :router         end
               | 
               | but that's a preference.
        
               | sodapopcan wrote:
               | You can do that if you want. Just remove `def router`
               | from `MyAppWeb` move its contents over to a custom
               | module:                   defmodule MyAppWeb.Router do
               | defmacro __using__(_) do             quote do
               | use Phoenix.Router, helpers: false
               | import Plug.Conn               import Phoenix.Controller
               | import Phoenix.LiveView.Router             end
               | end         end
               | 
               | But why the dislike for passing a second argument to
               | `use`? It keeps everything together pretty nicely.
        
           | jrochkind1 wrote:
           | > So long as the documentation is good, I don't really care
           | how the library itself is implemented.
           | 
           | I don't have experience in Elixir, but in my general
           | experience what you say is fine until you need to debug
           | something going wrong (or something you don't understand and
           | _think_ is going wrong) in a library, which always happens
           | eventually, no? Or until you want to PR a feature, etc.
        
             | sodapopcan wrote:
             | Those are fair points. In terms of PRing, though, I do
             | think that people are a little too "afraid" of macros. It
             | sometimes feels like people won't learn them out of of
             | principle which is a shame as they aren't that complicated.
             | Though anyone trying to navigate nested macros definitely
             | has my sympathy.
             | 
             | No matter how slice it, however, macros are a massive part
             | of what makes Elixir Elixir. A large portion of the
             | language's "keywords" are just macros and they reduce a lot
             | of the boilerplate Erlang forces you to write.
        
               | throwawaymaths wrote:
               | EEx does macros well. Note that EEx.function_from_x makes
               | you declare the name of the function it instantiates, so
               | it's searchable.
               | 
               | GenServer is kind of a "bad example" of a macro. It
               | creates a _totally hidden_ function. Though I guess to be
               | fair 99.9% of the time you really shouldn 't be writing
               | genservers in elixir.
        
               | AlchemistCamp wrote:
               | > 99.9% of the time you really shouldn't be writing
               | genservers in elixir
               | 
               | Woah! Why is that?
               | 
               | I've written at least one GenServer in nearly all the
               | Elixir projects I've worked on. They seem like one of the
               | base building-blocks to me. Also, if you squint a bit,
               | you'll see that many libraries you're working with are
               | essentially exposing a GenServer interface, with a few
               | extra features.
        
               | pests wrote:
               | The only thing I can think of is when developers overuse
               | genserver not realizing it's involving another process
               | and then serializing your requests (behind a queue even)
               | into its mailbox. That may be desirable for some but in-
               | process handling can sometimes be the better choice.
        
               | sodapopcan wrote:
               | > Also, if you squint a bit, you'll see that many
               | libraries you're working with are essentially exposing a
               | GenServer interface, with a few extra features.
               | 
               | Like LiveViews :)
        
             | throwawaymaths wrote:
             | Your intuition as a nom-elixir user is absolutely correct.
             | However it's worth saying that as a working dev, there's
             | almost never a problem in the core++ libraries.
             | 
             | Edit: lol looking at the log in elixir slack, and one of
             | the most recent posts is exactly trying to debug something
             | too magical in one of the aformentioned non-core++
             | libries!!
        
         | troupo wrote:
         | > now most recently ash
         | 
         | I've been using Ash in a side project and it's slowly growing
         | on me. You have to twist your brain a bit to grok it (and I
         | haven't, not fully).
         | 
         | Pros:
         | 
         | - a lot of things happen where you want them to happen.
         | 
         | I found that writing stuff with Ecto involves more boilerplate
         | than with Ash because you have to write your queries, and your
         | changelogs, and your API accesses, and wire them together, but
         | what if you want a separate API.... With Ash it's a single
         | resource with a few macros.
         | 
         | - quite a few escape hatches into regular Elixir
         | 
         | You don't want magic behind actions? There are several ways to
         | hook into what's happening, or even write everything manually.
         | And to the calling code... it will still look the same
         | 
         | - Despite all the macros the errors are usually quite good and
         | pinpoint the problems
         | 
         | Cons:
         | 
         | - too few people who truly understand Ash
         | 
         | - documentation is often too terse and concise. But you can't
         | really blame the author who is doing _a lot_
         | 
         | - errors are not always good :)
         | 
         | I do agree with you on overreliance on macros in parts of the
         | ecosystem
        
       | CyberDildonics wrote:
       | Elixir seems to benchmark as half the speed of python, which
       | would put it about 100x to 200x slower than C++. That's a lot of
       | speed to give up for the silver bullet promise of immutable data
       | structures (which I've never understood the appeal of in the
       | first place).
       | 
       | https://elixirforum.com/t/elixir-vs-python-performance-bench...
        
         | elcritch wrote:
         | It's unclear why the techempower gives low performance for
         | elixir / phoenix. But from what I've heard is that in real
         | world applications the performance tends to scale much better
         | than Python or Ruby.
        
           | CyberDildonics wrote:
           | The link is about execution speed, I think if you start
           | talking about 'scale' that's a diversion, since that isn't
           | about the language and is more about the architecture of the
           | program.
        
           | BaculumMeumEst wrote:
           | it's because the people who contribute to techempower
           | benchmarks are zealots who believe that it's far more useful
           | and important to show their One True Language in the Best
           | Possible Light than to give you a useful benchmark. take a
           | look at the source code for some of them and see for
           | yourself.
        
       | stilwelldotdev wrote:
       | I've landed on SvelteKit and classless CSS for most of my hobby
       | projects.
       | 
       | I am interested in Elixir though, especially Phoenix, but found
       | it to be difficult to manage and get started with in Windows.
       | 
       | Still looking for the easy way into learning to work with web
       | sockets as a 41 year old man with very little spare time.
        
         | _joel wrote:
         | WSL2 should get you going?
        
           | freedomben wrote:
           | That's what I would suggest as well. WSL2 and use asdf[1] to
           | manage the erlang/elixir versions.
           | 
           | You could also use containers pretty easily as well with
           | docker or podman for windows and the official Elixir
           | images[2].
           | 
           | [1]: https://github.com/asdf-vm/asdf
           | 
           | [2]: https://hub.docker.com/_/elixir
        
         | victorbjorklund wrote:
         | What is "classless CSS"? Just using style attributes?
        
           | tommica wrote:
           | Probably just a css file that styles the html elements only
           | without using any classes
        
         | CollinEMac wrote:
         | I'm using Phoenix for my side project on a Windows machine. It
         | hasn't been too problematic for me. Maybe something changed
         | since you've tried it.
        
           | OkayPhysicist wrote:
           | There used to be a couple pain points when working with
           | Phoenix on Windows. The bcrypt library wouldn't build,
           | something needed to be run in Administrator mode to establish
           | their symlink workaround, and PostgreSQL is a little more
           | irritable on Windows. SASS (some node dependency in the
           | Javascript asset managing stuff) also flat out didn't work on
           | windows, but there was a drop-in replacement.
           | 
           | I know the SASS issue was solved (as a side effect of
           | eliminating the node dependency), and I believe the bcrypt
           | issue was, too.
        
         | toldyouso2022 wrote:
         | Use virtuabox and make a vm with ubuntu, install elixir and
         | connect via ssh. This is what I did when I wanted to try it out
         | but only had win8
        
       | [deleted]
        
       | whalesalad wrote:
       | The a-ha moment when you grok "Elixir is actually a Lisp" is very
       | exciting indeed. It's a beautiful language that fits all of its
       | elements together so nicely.
        
       | bmitc wrote:
       | Elixir, other than the language itself, has wonderful developer
       | tooling that's all written and configured in the language itself.
       | It makes me feel really comfortable because it's all right there.
       | You don't need external scripting languages. For some
       | programming, you don't even need external libraries sometimes. It
       | all feels very OS like, not to mention the OS-like nature of the
       | BEAM.
       | 
       | If you're on the fence on Erlang or Elixir, watch _The Soul of
       | Erlang and Elixir_ by Sasa Juric: https://youtu.be/JvBT4XBdoUE
       | 
       | If it doesn't make you excited about a language, I don't know
       | what will. It is an astounding feat that the Erlang team at
       | Ericsson were so ahead of the curve and remain so today.
        
         | macintux wrote:
         | I absolutely love Erlang. It's a succinct, powerful, amazingly
         | well-thought-out system design with a VM that is very
         | complementary.
         | 
         | I just can't get past all the extra verbosity of Elixir, but
         | this writeup gives me hope that someday I will.
        
       | chubot wrote:
       | I'm also looking at Elixir and Phoenix (coming from Python/C++),
       | and it looks cool. Doing realtime features with Python requires
       | something like Tornado / asyncio, which isn't ideal IMO.
       | 
       | I'm all for the immutable / message-passing architecture in the
       | large, but I wish that you could just write Python-style code
       | within processes. The VM copies all data structures at process
       | boundaries anyway.
       | 
       | I think that language would be very popular!
       | 
       | I wrote Lisp 20 years ago, before Python, but now it feels a
       | little annoying to "invert" all my code, for what seems like no
       | benefit
       | 
       | e.g. from https://learnxinyminutes.com/docs/elixir/
       | defmodule Recursion do           def sum_list([head | tail], acc)
       | do             sum_list(tail, acc + head)           end
       | def sum_list([], acc) do            acc           end         end
       | 
       | I would rather just write                  def sum_list(L):
       | result = 0          for item in L:            result += item
       | return result
       | 
       | But then also have the Erlang VM to schedule processes and pass
       | immutable messages.
       | 
       | There is obviously a builtin in Python that does this, and I'm
       | sure there is a better way to do this in Elixir. But I think the
       | general principle does hold.
        
         | [deleted]
        
         | pythonaut_16 wrote:
         | Have you seen Elixir list comprehensions?                 iex>
         | for n <- 1..4, do: n*n       [1, 4, 9, 16]
         | 
         | Or for your example:                 iex> l = 1..3 # equivalent
         | to [1,2,3]       iex> Enum.reduce(l, fn item, acc -> acc + item
         | end)       # or       iex> Enum.reduce(l, &(&1+&2)       # or
         | the built in       iex> Enum.sum(l)       # all return:       6
         | 
         | https://elixir-lang.org/getting-started/comprehensions.html
         | https://hexdocs.pm/elixir/1.12/Enum.html#reduce/2
         | https://hexdocs.pm/elixir/1.12/Enum.html#sum/1
         | 
         | None of which take away from your point though: it's definitely
         | a different mental model than you use for Python/Go/Javascript.
        
           | [deleted]
        
         | mfitton wrote:
         | You might want to look into Ray. It's a Python library lets you
         | deploy actors (classes) and tasks (functions) and abstracts
         | away the management of resources, message passing, lets you
         | define automatic repairs, etc. that is entailed with deploying
         | an arbitrary amount of intercommunicating processes in Python.
         | 
         | Admittedly, I haven't worked with Erlang or Elixir, so their
         | solution to this might be much more usable. Ray is aimed
         | primarily at ML use-cases, though it is quite general.
        
         | jclem wrote:
         | You can reduce with list comprehensions in Elixir, but it's
         | uncommon to see:                   sum_list = fn list ->
         | for item <- list,               reduce: 0,               do:
         | (sum -> sum + item)         end              sum_list.([1,2,3])
         | 
         | Other comments are correct that `Enum.reduce/2` is probably
         | better:                   Enum.reduce(list, &(&1 + &2))
         | 
         | Obviously you don't have the flexibility / mutability you refer
         | to in other comments with either of these, but you can always
         | put more in your accumulator:
         | get_sum_and_update_count = fn list, map ->           for item
         | <- list,               reduce: {0, map},               do:
         | ({sum, map} -> {sum + item, Map.update(map, item, 1, &(&1 +
         | 1))})         end
         | 
         | (A contrived function that returns a list sum and an updated
         | map with the count of the values found in the list)
        
         | bcrosby95 wrote:
         | Built ins aside, I find most uses of recursion to be better
         | served by Enum.reduce.
        
           | chubot wrote:
           | Yeah I knew someone was going to say that (see last
           | sentence), but a for loop is more powerful and general than
           | reduce().
           | 
           | Mutability within the loop is useful, and it can be
           | controlled by processes and message passing.
        
             | bcrosby95 wrote:
             | I assumed you meant something like Enum.sum that completely
             | trivializes the code. In comparison, generic, higher level
             | functions are pretty fundamental to FP.
        
             | sodapopcan wrote:
             | I'm not sure "powerful" is the right word here, it's more a
             | matter of "what certain people are used to". If you want a
             | counter or whatever, you can use a tuple to give yourself
             | multiple accumulators. You could argue it's uglier, but I
             | wouldn't necessarily agree. It's something that is easy to
             | get used to if you remove the "but I'd rather just do it
             | this way" mindset.
        
             | throwawaymaths wrote:
             | the problem with a for loop is that it is inexplicit about
             | what from the outer scope can be mutated. Which isn't a
             | problem, for small functions but I have definitely seen
             | monster for loops in professionally written django code
             | with ~500 lines of code in the function.
             | 
             | Besides being in that magical sweet spot (executes
             | imperatively but reads declaratively), a reduce forces you
             | to declare ahead of time what things can be carried over
             | and mutated between each iteration.
             | 
             | > it can be controlled by processes and message passing.
             | 
             | DO NOT DO THIS YOU WILL REGRET THIS SIMCITY MEME
        
       | freedomben wrote:
       | What a terrific write up! I highly recommend the read.
       | 
       | I too had an ephiphany when I realized Elixir was actually a
       | Lisp. The language went from mildly interesting to "holy crap I
       | think this could be my favorite language." Add on some wildly
       | productive and pragmatic frameworks like Phoenix, Nerves, and
       | increasingly Nx, and you've got a hell of a toolkit.
       | 
       | My biggest criticism of Elixir has been the difficulty of writing
       | quick scripts, but that story has improved greatly over the last
       | couple of years. I still turn to Ruby for scripts (especially
       | since it's often present on systems and so easy to install), but
       | this is a good reminder that it's time to try Elixir again for
       | that. In some ways it may be better, such as dealing with
       | dependencies. For exmaple I try hard to avoid using any non-
       | standard libs with Ruby scripts so I can just use the system
       | ruby, and don't have to ship a Gemfile and/or install any gems,
       | or mess with chruby/asdf. With Elixir that story looks even
       | better since the deps can be part of the script itself.
        
         | sergiotapia wrote:
         | Here's a great repo showcasing how to use it more like a quick
         | scripting language.
         | https://github.com/wojtekmach/mix_install_examples
        
         | capableweb wrote:
         | > I too had an ephiphany when I realized Elixir was actually a
         | Lisp.
         | 
         | Is it actually? Last time I looked at Elixir (granted, that was
         | a while ago), the syntax for writing macros was different than
         | the syntax for writing ordinary code, so it fails even at a
         | simple thing like that, it doesn't seem to support homogeneous
         | meta-programming at all.
         | 
         | But again, I feel like I might be wrong here and I'm happy to
         | be proven wrong.
        
           | bmitc wrote:
           | What is the actual failure? The macros are written with and
           | by processing the built-in data structures.
        
           | sodapopcan wrote:
           | Ya, it's not _actually_ a lisp. I can 't find the source but
           | Jose has stated part of the idea was to give you lisp-like
           | metaprogramming with a non-lisp syntax (sorry, Jose, if I
           | have mis-quoted).
           | 
           | Even the regular syntax is sort of lispish, though, if you
           | remove the syntactic sugar. It's all macros and
           | datastructres.                   defmodule Foo do
           | def bar do             "baz"           end         end
           | 
           | is really:                   defmodule Foo, do: (def bar, do:
           | "baz")
           | 
           | ...which is lispish if you squint the right way.
        
             | zambal wrote:
             | A bit pedantic I guess, but that still uses some syntactic
             | sugar (optional brackets and keyword syntax). Removing all
             | syntactic sugar would look like this:
             | defmodule(Foo, [{:do, def(:bar, [{:do, "baz"}])}])
             | 
             | Even aliases (like Foo) are also a kind of syntactic sugar
             | for a specific type of atom (Foo is actually the atom
             | :"Elixir.Foo")
        
               | sodapopcan wrote:
               | Ha, ya I meant remove the `do` sugar.
        
           | foldr wrote:
           | That's just syntax sugar. Even the original Lisp was supposed
           | to have sugar on top of S-expressions, although that never
           | really happened.
           | 
           | https://en.m.wikipedia.org/wiki/M-expression
        
             | jjtheblunt wrote:
             | I think Mathematica has had a slight variant since 1988
             | (i've been using it since then, but never M-expressions,
             | but they look awfully similar).
        
               | anamexis wrote:
               | It's listed under the "Implementations" section of that
               | wiki article.
        
           | pmarreck wrote:
           | You can write macros (as well as functions, actually) that
           | accept AST and emit transformed AST back. It has quote and
           | unquote. Turns out that it doesn't need homoiconicity to
           | accomplish Lisp-level macro capability, which means it has
           | all the power of a Lisp but with actual syntax (which is,
           | like it or not, more appealing to many people) in a language
           | with deep pattern-matching and completely immutable data
           | guarantees.
        
         | barkerja wrote:
         | > My biggest criticism of Elixir has been the difficulty of
         | writing quick scripts
         | 
         | Curious what you find to be the biggest pain point(s) here. Is
         | it runtime containment? Library access? Etc.
        
           | monsieurbanana wrote:
           | Is the size of the erlang vm one such point? I think I
           | remember reading it's about 500mb, and you won't find it
           | installed by default in many systems.
        
             | bongobingo1 wrote:
             | Most of my phoenix apps sit under or around 100mb resident,
             | and they load a fair bout more than a script probably
             | would.
        
             | square_usual wrote:
             | Startup time is another. For example:                   $
             | elixir test.exs         hello, world!              $
             | hyperfine "elixir test.exs"         Benchmark 1: elixir
             | test.exs           Time (mean +- s):     471.1 ms +-   2.6
             | ms    [User: 187.4 ms, System: 83.1 ms]           Range
             | (min ... max):   467.1 ms ... 475.6 ms    10 runs
             | 
             | Compared to:                   $ ruby test.rb
             | hello, world!              $ hyperfine "ruby test.rb"
             | Benchmark 1: ruby test.rb           Time (mean +- s):
             | 36.3 ms +-   2.6 ms    [User: 26.0 ms, System: 8.4 ms]
             | Range (min ... max):    34.5 ms ...  53.6 ms    53 runs
             | 
             | In practice, I've been able to get the ruby startup time to
             | as low as 6ms - this is what I use for scripts running as
             | keyboard macros, for example. I cannot practically use
             | elixir for that.
        
               | hosh wrote:
               | Huh, interesting. I bet for keyboard macros, it would
               | work better by invoking a call to something that is
               | already running to reduce startup time. Kinda like the
               | emacs server.
               | 
               | BEAM should still be able to compile new code on the fly,
               | for one-off scripts
        
               | square_usual wrote:
               | > keyboard macros [...] would work better by invoking a
               | call to something that is already running to reduce
               | startup time
               | 
               | Maybe, but that comes with two disadvantages:
               | 
               | - I would have to re-architect my scripts to work like
               | that, and run a server with uncertain memory costs
               | perpetually; and - I would have to use something with
               | faster start time to run the call on my keyboard macros,
               | e.g. bash, which would mean writing bash instead of
               | elixir/ruby and/or being clever.
        
               | barkerja wrote:
               | Using escript, I am able to almost halve the startup
               | time. But it's still ~4x slower than ruby.
               | hyperfine "./derp"         Benchmark 1: ./derp
               | Time (mean +- s):     241.0 ms +-   7.4 ms    [User:
               | 146.9 ms, System: 170.8 ms]           Range (min ...
               | max):   235.1 ms ... 261.7 ms    11 runs
        
         | bcardarella wrote:
         | For me Elixir's Livebook has become a killer "scripting" tool.
        
         | cutler wrote:
         | Re Elixir for scripting, what's the point? Procedural Ruby,
         | Perl, Python or bash have been around for decades and are
         | exactly what you need for short sysadmin scripts.
         | Elixir/Erlang's niche is massive lightweight conucurrency and
         | is the wrong tool for this domain.
        
           | travisgriggs wrote:
           | I often write some little toolets in Elixir, just to hone
           | skills and give myself an opportunity to explore the libray.
           | Often after I e first written it in Python. I agree it feels
           | a little misaligned, but it's nice to be able to use it for
           | other reasons.
        
           | epiccoleman wrote:
           | The Enumerable APIs, regex handling, low-bullshit functional
           | approach, and great REPL make it a pretty nice scripting
           | language. I've done quite a few Advent of Code puzzles with
           | it, and it always feels like such a nice multitool for
           | chewing up the input files into workable formats.
           | 
           | It's not the first tool I'd reach for, I'm still a filthy
           | bash hacker at heart, but I could definitely see using it for
           | the right problem.
           | 
           | It's also just fun to write, which is valuable in its own
           | way.
        
             | cutler wrote:
             | What you've described is functional-style/dry Ruby.
        
               | epiccoleman wrote:
               | Well, no, what I'm describing is Elixir.
               | 
               | If your point is that the potential use cases overlap too
               | much with Ruby, I mean, fine, write Ruby. I like Elixir
               | more. I'm not picking either language for pure
               | performance, but rather for ergonomic purposes, so we're
               | into kinda subjective territory.
        
         | malkosta wrote:
         | Problem with writing scripts in Erlang VM is the slow startup
         | time...it isn't suited for that. Although I love it for pretty
         | much everything else besides scripts and executables.
        
           | pmarreck wrote:
           | Yeah, this miffs me too (a half second startup time,
           | locally), which has got me even looking at languages like
           | Idris that can compile down to C and then thus to an instant-
           | start app.
        
           | ghayes wrote:
           | Also it's not the best for creating OS processes and/or
           | interacting with stdio.
        
         | jrochkind1 wrote:
         | > For exmaple I try hard to avoid using any non-standard libs
         | with Ruby scripts so I can just use the system ruby, and don't
         | have to ship a Gemfile and/or install any gems
         | 
         | The ruby "story" for Gemfile dependencies for single-file
         | scripts have gotten a BIT better since possibly last time you
         | looked at it.
         | 
         | It will of course necessarily involve installing gems still
         | though. Ideally for your use case, I feel like you'd want to
         | install them to a local (not system-default) location ... which
         | is ordinarily possible with bundler, but oddly the maintainers
         | seem to think it's an anti-use-case for inline bundler?
         | https://github.com/rubygems/bundler/issues/7131. I dunno.
         | 
         | Anyway, I put this here not to convince you, your decision is
         | reasonable, but just other info for other readers.
        
       | coolros wrote:
       | That was a good read, well done. I've been using Elixir for about
       | a year now and I just smile when I'm coding. I'm still a little
       | unsure about it's place and where it'll go, but I have loved
       | exploring and learning BEAM with a little nicer syntax. Jose is
       | great and watching the introduction of a type system is
       | interesting too
        
       | satvikpendem wrote:
       | Elixir is cool, I used to use it for web app backends before
       | adopting TypeScript and Rust. The reason I adopted them was the
       | same reason I stopped using Elixir after a while: type safety. It
       | was getting increasingly hard to be productive in Elixir in a
       | large application due to runtime type errors that are caught in
       | statically typed languages.
        
         | johnisgood wrote:
         | Strange, I cannot recall the last time I ran into one and I
         | write a lot of Erlang. Both Erlang and Elixir share the "Let It
         | Fail" philosophy, additionally it is also highly encouraged to
         | use pattern matching, guards, and error-handling techniques to
         | deal with potential type-related issues and errors.
         | 
         | On the other hand, I get it all the time with Python, for
         | example.
        
         | cpursley wrote:
         | I've found that pattern matching in the function head and
         | guards get you most of the way there.
        
           | satvikpendem wrote:
           | Yes however I get that in TS and Rust while also having
           | stronger type guarantees. I don't think pattern matching is
           | an alternative to static types, it's a supplement.
        
             | weatherlight wrote:
             | Rust, sure. Love me some Rust.
             | 
             | Typescript's type system isn't sound and you can still get
             | runtime errors. (Type systems should be bomb-proof or just
             | get out of the way.)
        
             | johnisgood wrote:
             | Well, I suppose to each their own. I use languages with and
             | without static typing. I love Ada the most though, because
             | the way you define types is very different from the most
             | widespread way. In Ada, you define the range.
             | 
             | Examples:                 type Day is         (Monday,
             | Tuesday,          Wednesday,          Thursday,
             | Friday,          Saturday,          Sunday);       subtype
             | Business_Day is Day range Monday .. Friday;       subtype
             | Weekend_Day is Day range Saturday .. Sunday;       subtype
             | Dice_Throw is Integer range 1 .. 6;            type
             | Arr_Type is array (Integer range <>) of Character;
             | type Color  is (White, Red, Yellow, Green, Blue, Brown,
             | Black);       type Column is range 1 .. 72;       type
             | Table  is array(1 .. 10) of Integer;            type
             | Device_Register is range 0 .. 2**5 - 1 with Size => 5;
             | type Commands is (Off, On);       type Commands2 is new
             | Integer with         Static_Predicate => Commands in 2 | 4;
        
         | hmmokidk wrote:
         | How tested were your applications?
        
       | jnsaff2 wrote:
       | If you want to get a mindbending experience of the articles "it's
       | macros all the way down" then here is one for you in glorious 3
       | minutes and 39 seconds:
       | https://www.youtube.com/watch?v=x5W3CmZJMLs
        
         | tommica wrote:
         | That's pretty cool!
        
       | pmarreck wrote:
       | It looks like it got HackerNews'd. The stack seems to be
       | Happstack, a Haskell lib.
       | 
       | Perhaps if it was served by Phoenix... /obvious comment is
       | obvious
        
         | hu3 wrote:
         | You're correct.
         | 
         | It says at the bottom: powered by https://github.com/jgm/gitit
         | 
         | Readme states that: "Gitit is a wiki program written in
         | Haskell. It uses Happstack for the web server and pandoc for
         | markup processing."
        
       | davidw wrote:
       | That's a pretty good write up.
       | 
       | There's a fine line between making things easier and more
       | readable and having less boilerplate code, and pouring a bit too
       | much magic and macros into things.
       | 
       | I'm always curious to see what people do with Elixir. The BEAM
       | environment offers a lot in terms of a platform, but if you're
       | just using it to serve web dynamic web pages, Rails is going to
       | be a better pick in _some_ circumstances because of the huge
       | number of libraries, people who know it, documentation, hosting
       | and the rest of the ecosystem.
        
         | pdimitar wrote:
         | The transparent parallelism makes it an amazing fit for pretty
         | much anything and everything that doesn't require minimum
         | system resources and microsecond-level of response times.
         | 
         | 1. Web apps work awesomely because they tolerate sudden bursts
         | of load much, much better than Rails. Rails deployments
         | regularly fall over on bursty workloads unless complex load-
         | balancing setups have been put in front of them.
         | 
         | 2. Which brings me to: operations / infra story is much
         | simpler, and it is thus cheaper and easier to maintain Elixir
         | apps, even when they span multiple nodes (because Erlang's
         | builtin mechanism to do mesh networking / distribution works
         | well enough for 99% of the projects out there).
         | 
         | 3. Complex service trees f.ex. scrapers that also present their
         | data in a visual CMS backoffice UI and background tasks
         | infrastructure -- all of that can live on literally the same
         | node, share the same code repo and be very easy to manage and
         | maintain as a result.
         | 
         | 4. Oh, that also reminds me: almost anything and everything you
         | would need Redis for, you can have it natively with
         | Erlang/Elixir.
         | 
         | 5. Corollary to point 3: long-lived daemons that are not even
         | web apps / APIs work really well under Elixir due to the
         | supervision tree guarantees of Erlang's underlying OTP
         | framework. If you configure it well (the defaults are not
         | always optimal) you can have your invisible mesh of services
         | survive extended outages of the 3rd party APIs it depends on.
         | 
         | 6. In the last years, LiveView and Livebooks are amazing
         | additions that help severely reduce the need of JS and provide
         | an alternative to Jupyter Notebooks, respectively. Though it
         | has to be said that LiveView works best when the latencies to
         | the backend aren't too big, say, 200ms or less. Beyond one
         | certain human perception threshold it starts to feel sluggish
         | however.
         | 
         | I could go on and on and give plenty of examples from my
         | career. I've replaced a lot of shell scripts and PHP / Python /
         | JS services with Elixir, and each migration was a crushing
         | success in every way. We're talking 15+ such projects. Only 1-2
         | of them got back to their original language simply because the
         | companies / teams were too risk-averse and didn't want to hire
         | Elixir devs (or train their current people). But the network
         | effects are always a chicken-and-egg problem; if people never
         | want to bet something on the tech then it obviously is never
         | going to be appealing to them.
         | 
         | There are many who made the plunge though and are happy with
         | the results.
        
           | davidw wrote:
           | > If you configure it well (the defaults are not always
           | optimal) you can have your invisible mesh of services survive
           | extended outages of the 3rd party APIs it depends on.
           | 
           | This is something that annoyed me a bit with OTP. The basic
           | strategies aren't really enough for that, so you need
           | something like https://github.com/jlouis/fuse
           | 
           | I wrote something like that myself, but it hasn't seen a ton
           | of use: https://github.com/davidw/hardcore
        
         | megaboy101 wrote:
         | Where I previously worked we used Elixir as the backend for a
         | early-stage social app.
         | 
         | We only really encountered the lack-of-libraries issue a single
         | time (we needed a Neo4j driver that supported their hosting
         | platform).
         | 
         | But aside from that, Elixir was a great choice and served us
         | well. When our app went semi-viral all we needed to do was
         | increase our instance size in AWS, never really needed to worry
         | about horizontal scaling thankfully.
         | 
         | Our app also needed a lot of realtime messaging and updates,
         | which was genuinely a breeze with Phoenix. I don't think I
         | could ever to back to trying to finagle a websocket API in
         | Python.
        
           | hosh wrote:
           | If anything, scaling Elixir apps favors vertical scaling.
           | Horizontal scaling starts hitting the limits of dist erlang
           | (since, unless you restrict the topolog, every node connects
           | with every other node).
           | 
           | It makes for an interesting time when deploying to
           | Kubernetes. But we figured out how to increase the number of
           | cores per erl node during peak daily traffic.
           | 
           | I'm working for a Nodejs shop now. For all its use of async
           | stuff, it simply does not scale as well as Elixir (not to
           | mention the deep dysfunctions in the Nodejs ecosystem).
        
             | dsiegel2275 wrote:
             | If I recall the things I've read on this in the past, the
             | horizontal scaling limitations of distributed Erlang are
             | encountered around like 500 to 1,000 nodes? Which I have to
             | imagine means the large, large majority of shops using
             | Elixir and scaling horizontally will be just fine, as they
             | are typically in the size of 2 - 10, or maybe 20 nodes.
        
         | hosh wrote:
         | Having done both Rails and Elixir, Elixir is vastly easier to
         | scale. Not just because it can use up all the available cores,
         | but also because a REPL in a production environment makes
         | troubleshooting and identifying bottlenecks easier. When I
         | scaled Rails, it was a struggle, and the epiphany I had when I
         | had to modify how Sidekick worked was that Elixir and Erlang
         | had built-in primitives to do what is major refactor of
         | Sidekick to get Sidekick to do what I want.
         | 
         | One of the things I had success with in a non-web applications
         | is writing Kubernetes Operators in Elixir. Though I also want
         | to experiment with the embedded Prolog-in-Elixir for those.
        
         | cschmatzler wrote:
         | Phoenix is obviously "the big thing" and no other
         | language/framework combination has something as good as
         | LiveView. Rails cannot compete there. Other than that, building
         | Livebook apps for our customer success team has been really
         | great and easy.
         | 
         | There's quite a big push for ML in Elixir right now, and then
         | there's also Nerves for embedded programming, which I've never
         | dabbled in but it looks nice.
        
           | cultofmetatron wrote:
           | ecto is also just an amazing db wrapper in general. you
           | basically write sql in elixir which means you can optimize
           | the crap out of your queries and its easy to steop down to
           | actual sql where needed via fragments.
        
             | hosh wrote:
             | And you can still use composable queries if you still want
             | to (equivalent to Rail's named scopes).
        
           | slekker wrote:
           | Do you have any write up about Livebooks for your CS team?
           | Sounds like an interesting use case!
        
           | OkayPhysicist wrote:
           | LiveView is definitely Elixir's killer app. It's what takes
           | Phoenix from "a really good web framework" to "the singular
           | best web framework", in my experience. Ecto is also a best-
           | in-class data-layer adapter (ORM seems wrong and reductive).
        
           | metaltyphoon wrote:
           | > no other language/framework combination has something as
           | good as LiveView
           | 
           | You just have to look. Blazor does what LiveView do and on
           | upcoming. NET 8 it will leapfrog it.
        
         | sodapopcan wrote:
         | > Rails is going to be a better pick in some circumstances
         | because of the huge number of libraries.
         | 
         | This isn't really as big a problem as many people think. I've
         | been out of Rails for a while now but haven't really felt the
         | pain of missing anything with Phoenix. I've noticed there _aren
         | 't_ often Elixir wrappers around third party APIs, but those
         | are really not a big deal to create a small version on your own
         | with only what you need. I always used to wrap the wrappers
         | anyway! As far as UI stuff goes, there are actually a lot of
         | really nice vanilla JS libs out there which play really nicely
         | with LiveView's JS hooks.
         | 
         | I would be interested to hear what people have been _sorely_
         | missing, though.
         | 
         | EDIT: Said "are" when I meant "aren't"
        
           | arrowsmith wrote:
           | Your experience matches mine. And ChatGPT has been a game-
           | changer - if there isn't an Elixir library for some third-
           | party API, GPT is very good at generating some wrapper
           | functions in Elixir using the API docs.
        
           | davidw wrote:
           | Oh, I don't think the library thing and ecosystem is really
           | an obstacle for using Elixir so much as it makes Rails a
           | 'safe bet'.
           | 
           | If I'm putting on my business hat, I need a reason to use
           | Elixir instead of Rails and that probably has something to do
           | with a better concurrency story, but I'm always curious to
           | hear what other people are getting out of it.
           | 
           | My previous experience with BEAM was using Erlang in a semi-
           | embedded environment and it was fantastic for that. Solid,
           | dependable, deterministic, great response times... all of
           | that. But while we did have a web interface to the system, it
           | wasn't a web site.
        
             | bcrosby95 wrote:
             | For us its the simplified production environment. We use
             | BEAM's clustering capability to forgo things like redis
             | and/or a message queue. It probably doesn't matter for
             | every company, but it helps for us where we have zero full
             | time ops people.
        
               | hmmokidk wrote:
               | And if you forgo those things you can easily test them.
        
               | davidw wrote:
               | That's a pretty good reason. Some people might react
               | "well, you're going to need those things broken out
               | anyway as you scale" or something to that effect, but it
               | can be really nice to just not need them until you have
               | scaled further. There are plenty of smaller applications
               | where you just don't want or need all the extras and the
               | longer you can keep it simpler, the better off you are.
        
               | sodapopcan wrote:
               | Ya, this is one big bonus in my eyes. I have certainly
               | hear the argument several times that "installing redis is
               | really easy" and it is! But it's another moving part that
               | often isn't necessary with BEAM.
               | 
               | In a current project I'm also able to use OTP to create a
               | single microservice for my monolith that runs on its own
               | node and the two can communicate with run-of-the-mill
               | message passing without the need for an HTTP API.
        
               | OkayPhysicist wrote:
               | The BEAM's multi-node scaling works really well. The
               | argument that you'll need to break things out if you get
               | big enough doesn't really hold water.
        
               | hosh wrote:
               | And even if you need to break things out, you can build
               | different variants of distributions that can all still
               | work together.
        
               | davidw wrote:
               | BEAM isn't magic scaling sauce, and you're going to run
               | into trouble if you get big enough. But that's a "good
               | problem to have". And it's probably 'enough' for many
               | businesses as-is.
        
               | OkayPhysicist wrote:
               | It's not magic, but neither are any of the alternatives.
               | There needs to be a compelling "my constellation of
               | services written in a variety of languages, communicating
               | via a half-baked homebrew collection of API calls beats a
               | constellation of distributed Erlang applications
               | communicating via message passing over the BEAM" to claim
               | that Erlang has scaling issues relative to the
               | alternative.
               | 
               | The reality is that asynchronous, parallel, distributed
               | computing is hard, Erlang makes it easier. Not easy, but
               | easier.
        
               | toast0 wrote:
               | > Some people might react "well, you're going to need
               | those things broken out anyway as you scale" or something
               | to that effect, but it can be really nice to just not
               | need them until you have scaled further.
               | 
               | Dist messaging and mnesia scale pretty far. Although it
               | must be noted that they were original built around rock
               | solid networking (two nodes in one chasis), so if your
               | networking is flakey, you have to handle that; my
               | recommendation is to make your network not flakey, but
               | that's easier to say than it is to do.
        
               | davidw wrote:
               | I would pair BEAM with Postgres, not Mnesia as that's
               | going to limit you in a lot of ways. Unless you
               | reaaaaaally know what you're doing.
        
               | toast0 wrote:
               | Well, I like to think I know what I'm doing. And I've
               | participated in some big Mnesia operations.
               | 
               | That said, redis is in memory key-value, and Mnesia does
               | in memory key-value too. If you're using Postgres's
               | relational stuff or data bigger than memory, that's a
               | different thing. Mnesia has some relational facilities,
               | but I dunno if anybody uses them much; mnesia can use
               | disc_only_copies, but that's not a good time. Of course,
               | memory only gets you pretty big tables these days; I ran
               | some mnesia nodes with 768GB, but a couple TB isn't too
               | hard to put together these days.
        
             | arrowsmith wrote:
             | My reason to use Phoenix instead of Rails: development
             | speed. I'm just so blazingly productive in Phoenix that
             | nothing else compares, including Rails. Every time I'm
             | forced to develop in another framework I now get
             | agonisingly frustrated by how long it takes to get anything
             | done.
        
       | throwanem wrote:
       | Seems struggling at the moment. Archive link:
       | https://web.archive.org/web/20230803145324/https://wiki.alop...
        
       | mcguire wrote:
       | " _This is the root of my curmudgeoniness: Magic is never worth
       | it. 99% of the time, Magic breaks. And when it does, and someone
       | inevitably asks me to help fix it, I do it by getting out the
       | machete and chopping out all the happy shiny convenient shit
       | until you can see what is actually going on. And when you dig
       | through the Magic and try to figure out what the hell is actually
       | going on, most of the time it's either stupid and broken by
       | design, or it's not very magical at all and you're just like "why
       | didn't you just say this in the first place?"_
       | 
       | " _Over and over again, it turns out that there is no such thing
       | as Magic, and anyone who says otherwise is skimming over details
       | that will bite you in the ass later on. This is fine for many
       | purposes, because 90% of programs are small hacks and one-off
       | tools and so "later" very seldom actually happens._ "
       | 
       | Oh, yeah. This. So much this. A dump-truck load of this.
       | 
       | Even better when everybody is using different Magic, or the guy
       | who set up this Magic left two years ago and everything has been
       | done my cargo-cult since.
        
       | weatherlight wrote:
       | Elixir is probably my favorite dynamic language and a lot of that
       | has to do with the community that sprung up around it. I wish it
       | were more popular.
        
         | hosh wrote:
         | I don't wish it to be super popular.
         | 
         | I heard the argument before that JS (and Nodejs) is popular
         | (top 3), so you should go into it.
         | 
         | I'm now in a nodejs shop. Turns out, the way Erlang and Elixir
         | is designed serves as a filtering function for hiring. People
         | who just wants to code without putting a lot of thought into
         | it, don't go into Elixir and land in JS instead. (All the
         | current coworkers I have wants to make things better but we are
         | saddled with code that has been ... oddly written)
         | 
         | At the last Elixir shop I was at, I was part of a small crew
         | that was more experienced as a whole than other shops I have
         | been at. And I liked it.
        
           | no_wizard wrote:
           | Popularity is a multiple faceted issue w/r/t quality of
           | engineers in any given language.
           | 
           | One caveat to any of it is the easier a language is to grok
           | and the more use cases it has, the more likely it will
           | attract all types of developers and there will always be more
           | "bottom end" developers than "top end" developers, as is
           | patterned out in any large distribution.
           | 
           | That said, here's some facets to consider about this
           | 
           | - Its not likely its the language (or to be charitable, not
           | _just_ the language) at play here. As noted above, the more
           | popular something is, the more likely you end up with a wider
           | varieties of folks at very different backgrounds  / skill
           | levels etc. Python and PHP have similar issues.
           | 
           | - The more popular the language is, is often correlated to
           | its use cases. For example, JavaScript is hugely popular in a
           | wide swath of problem domains, from the server, to the web
           | (its de facto monopoly right now) to desktop apps to even now
           | mobile (Ionic, NativeScript etc). This leads to the top
           | developers in the language often going to very lucrative
           | positions that one would also presumably have to be working
           | alongside or as part of to be working with them
           | 
           | - Its harder in a bigger pool to work with the top N % of
           | developers in any given language or (better yet, any given
           | environment / problem space deploying that language as part
           | of its core technological backbone). The big "sea" in the
           | middle is what you're most likely to be apart of
           | 
           | I think smaller communities benefit from organic interest,
           | people who are enthusiastic to use the technology and
           | therefore often the perceived quality of those developers is
           | higher (and often it does correlate, see: the history of
           | Clojure)
           | 
           | I don't think a language in and of itself is to blame, except
           | in that maybe, because some languages like Python and
           | JavaScript are so easy to pickup as opposed to say, Java,
           | Kotlin, C# or Rust, that they attract more developers in
           | general. That said, I think its the laws of distribution at
           | work, and not really the driven by the language per se.
        
       ___________________________________________________________________
       (page generated 2023-08-03 23:00 UTC)