Hacker News new | ask | show | jobs
by Thaxll 2540 days ago
- deployment is terrible like really bad

- average performance ( like 10x slower than Java even worse for CPU intensive tasks )

- dynamic language ( this is the worst part ), working on large code base means problems ahead

- lot of features from BEAM / OTP that are not that useful and done better on modern cloud platforms ( Kubernetes for instance does a lot of similar things but better and more flexible, apply to any languages ) People like to talk about hot code update which imo is a terrible idea, you should have a proper CI/CD pipeline to do that and not rely on dangerous features like that.

- lack of ecosystem / libraries

- it's FP, I count that as a personal cons

5 comments

> - dynamic language ( this is the worst part ), working on large code base means problems ahead

IMO, I the fact that Elixir is a dynamic language is not that much a problem thanks to pattern matching.

Elixir's pattern matching is really powerful, allowing for things like:

    def move(_state, _x, _y, kind) when kind not in ~w(forward backwards) do
      {:error, :invalid_move_kind}
    end

    def move(state, x, y, kind) do
      get(state, x, y)
      |> do_move(state, x, y, kind)
    end
In this case, I am asserting that "kind" is either string "forward" or "backwards". If not, I return the an error :invalid_move_kind. I don't need to check if pos is nil or not string, since I can assert using pattern matching that everything with my inputs are right.

Also, there are things like structs:

    defmodule RobotVsDinosaurs.Robot do
      alias RobotVsDinosaurs.Robot

      @enforce_keys [:pos]
      defstruct name: nil, pos: nil

      def set(state, x, y, robot = %Robot{}) do
        case Matrix.elem(state, x, y) do
          %Robot{} -> {:ok, Matrix.set(state, x, y, robot)}
          _ -> {:error, :invalid_type}
        end
      end
    end
What I am saying in the code above is that %Robot{} must have a :name and a :pos entries, and by default they're nil. However, to create a new %Robot{}, :pos must be different them nil. And of course, I can pattern match if my input is actually a %Robot{} and not a simply dict.

You can also do crazy things like pattern matching if a byte array have some specific characteristics, like a magic number.

So while I think it would be nice for Elixir to have types (there is Dialyzer however it is kinda a PITA to use), it is less necessary than Python/Ruby/Javascript thanks to the above.

I agree, and what's interesting about this technique is that you can guard against specific values instead of just types.
Regarding Elixir being a dynamic language, I've programmed in Java, C#, and other strongly typed languages as well as Ruby, Python, Elixir, and other dynamic languages since the mid 90s. Throughout my entire career, I cannot think of a single time when I've thought, "It would be so much nicer if this language was statically typed." It just hasn't ever been an issue for me.

If typing is something you really want to catch at compile time, and pattern-matching and guards aren't enough for you, you can always define Dialyzer specs and run Dialyzer during your build process. I'm currently working on an Elixir codebase that does this, but I've worked on others that don't, and I haven't seen much of a difference either way. Personally, I think strong typing is overrated.

Not to mention that for a decade and more, HN was full of "dynamic languages are the best! Who needs types! Dynamic FTW!" comments and articles. It wasn't fully accurate, and neither is the about-face to "Types FTW! Typing is the best thing ever!".

I have come to enjoy the more self-documenting nature of static typing (in PHP of all languages). Yesterday I worked on a legacy project with no typing, and to determine what was passed to an untyped method (with no documentation) required running the interactive debugger and inspecting what was passed in different scenarios...

Well I mean there are a class of bugs they help to catch but with pattern matching it really don't come up very often. Just don't match the values you don't want. Sure it's a runtime error but you'll catch them pretty fast and elixir is fault tolerant.
> deployment is terrible like really bad

I've seen this stated many times as one of the big drawbacks of Beam languages. But using Distillery with Elixir, it's very easy to generate a release that's completely self contained. Just extract a tarball on a freshly installed system and you are ready to go. If your target platform differs from the one you are compiling your project on, there are various options for cross compiling too

We just bumped to elixir 1.9 and I'm enjoying seamlessly deploying to our dev environment with a single command from Linux and my juniors are working on getting it to go for Mac via vagrant.
Distillery is a pain to set up, but once done, deployment is as easy as:

    mix edeliver build release production && mix edeliver deploy release production
I've set this up as an alias in mix.exs to I just have to type:

    mix deploy
1.9 makes configuration easier than Distillery, I think.
1.9 does some of, but not all of what Distillery does. I'm still using Distillery because it supports upgrades instead of just full releases.
> average performance ( like 10x slower than Java even worse for CPU intensive tasks )

Urgh, that's a disaster.

How confident are you that what you are doing is CPU intensive?