Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Having worked with both to create the same system (building a game server) I've found Clojure actually sits better with the functional thinking style (1 data structure, 100 functions).

While Phoenix was the killer app for Elixir, and Elixir has far superior readability (using the Ruby syntax); there were couple of things that were off-putting and I struggled with them.

1. everything is inside a module was an unnecessary distraction

2. And then the separation between anonymous and named functions simply were unnecessary

3. And that I would have to declare the data / record inside a module (??)

Elixir felt like a functional language un-necessarily trying to look like a class based language.

I sometimes feel that had Elixir had only supported functions outside of modules... oh that freedom.

But some of the thought that went into Flow, Channels (which has become the de riguere now), mix (developer ergonomics ftw), those micro-second latency responses, distillery are still too classy and amazing.



> Elixir felt like a functional language un-necessarily trying to look like a class based language.

Not really. Named functions live in modules because that is how it is done in Erlang; Elixir is compiled to Erlang's abstract syntax. In practice does anyone define Clojure functions outside of a namespace? Haskell functions are always defined in modules too, do you think they got that from class based languages?


The problem here is that its inconvinient to define a function at the Elixir REPL because it demands that it be put inside a module.

Clojure REPLS allow switching the namespace, and anything you define goes intoo the current namespace. So it is more ergonomic.


IEx will let you define a module at the REPL. Combine that with a macro (exercise for reader) in your .iex.exs which expands a function into a module definition and imports it and you're in business.

    iex(1)> defmodule Foo, do: def bar(x), do: x + 1
    {:module, Foo,
     <<70, 79, 82, 49, 0, 0, 4, 192, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 135,
       0, 0, 0, 15, 10, 69, 108, 105, 120, 105, 114, 46, 70, 111, 111, 8, 95, 95,
       105, 110, 102, 111, 95, 95, 10, 97, 116, ...>>, {:bar, 1}}
    iex(2)> Foo.bar(1)
    2
    
    iex(3)> import Foo
    Foo
    iex(4)> bar(1)
    2


Yup, like I said, not as ergonomic as Clojure.

In clojure, it is:

    user> (defn bar [x] (+ x 1))
If you want it inside a namespace named foo, then it is:

    user> (in-ns 'foo)
    foo> (defn bar [x] (+ x 1))


I agree Clojure has a better REPL experience than Elixir. But in Elixir REPL for a quick and dirty function you'd probably just do

    >bar = fn x -> x + 1 end
The most unfortunate thing though is then you have to have a different calling convention. Its the greatest flaw in Elixir by far but they didn't have a reasonable alternative given the constraints of Erlang.

Still for defining a named function in the REPL its the same in Haskell and most other languages I believe that you can't define a new named function or add a function to a module in the REPL, though at least in Haskell the calling convention for a variable bound to a lambda is the same as for a named top-level function. LISPs have always had a different notion of how the REPL integrates into the development experience of a running program, and I don't think its really been replicated elsewhere.


Or maybe go with the shorter anonymous function syntax:

bar = &(&1 + 1)


If we're playing code golf, then in Clojure it is:

    (def bar #(+ % 1))
or even

    (def bar inc)
but the difference is that in Clojure, all of these are `IFn`s, and have the same calling syntax, unlike Elixir.


You may be "playing code golf", but I generally just use the capture syntax where the compactness aids readability. For example, a function that takes two arguments and returns their product could be written as

fn x, y -> x * y end

or

&(&1 * &2)

When used inside a map or reduce or when the function is a direct mathematical operation on its arguments, it can be a bit quicker to parse the capture syntax than the fn ... end syntax.


True. The heritage of erlang is undeniable here.

In Clojure too, the fns, records everything live inside a namespace but that is a modularity mechanism for code organisation.


I had most of these concerns when I was early learning the language. I found it annoying to have everything in modules. Now, however, I've come to appreciate the organization and structure that this forces upon the programmer.

It makes me structure my code and group related concerns at time of writing. I now code my functions as a working collective rather than individual items.

And with .exs files, you can have multiple modules in one file for quick scripting.[0]

[0]https://github.com/matteing/stack/blob/main/server/boilerpla...


This was one of my big impressions of Elixir. It forces you into so many things that improve long term maintainability.


Which is exactly what class based modularity provides


Sounds like you would love Nim.

You can just ignore modules/namespaces. While you have some procedures private to the file, you can expose them and they're just in the global namespace.


Maybe my enjoyment with Nim is partly due to the (awesome!) boringness of Elixir at times. I write Elixir code. It mostly just works with a few simple abstractions. Nim's more fun for MCU's and fast code where allocations count and I don't care about scalability of the application as much. I rather enjoy both.


I have had the same experience!

The distinction b/w anonymous and named functions is especially icky.

I also agree that Elixir leads to more readable code, lots of people in the Clojure community tend to write dense one liners to appear "cool".


I have a feeling it’s not to appear “cool,” but because when you’re writing code there is a tendency to prefer higher density.

Why?

Because higher density makes it easier to see the entirety of a context: more code on the screen makes it easier to spot the relationships.

This happens in other languages too, of course, but it’s easy to see why Closure pushes flow in that direction.


I've seen inscrutable one-liners with Elixir's capture syntax, too (and written some myself :) )


Like others all of my Clojure code was in namespaces so I see it as a wash between the two. In practice I cannot imagine any real app not making use of such modularity.

I too found the "." syntax for anonymous functions a bit jarring at first. Why treat them differently? In practice I don't even notice it now. It's never been confusing, it's just a wart.

Also, I found the one-struct-per-module thing a bit odd to begin with but in practice it makes a lot of sense. Also since you can put modules inside modules it's no encumberance if you want to declare a number of related structs. Again, once I was used to it I apprecitated the simplicity.

I disagree with your characterisation: I perceive no "class-based"'ness about Elixir. Do you have some examples? Perhaps there is somethign I have missed. So far, given that it's not exposing a class based system underneath, Elixir has seemed even further from this than Clojure.

And I have, in general, found the tooling support friendlier for Elixir. The only thing that I really gripe about is the inability to communicate between editor and REPL.


My “impression” of class based comes from the usage that defrecord was to be inside a defmodule only; not as free floating records.

About the tooling definitely yes. Elixir is pretty pretty good; at compile, build and employ time.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: