[HN Gopher] Elixir protocols vs. Clojure multimethods
___________________________________________________________________
Elixir protocols vs. Clojure multimethods
Author : sandbags
Score : 142 points
Date : 2021-07-17 11:47 UTC (11 hours ago)
(HTM) web link (mattmower.com)
(TXT) w3m dump (mattmower.com)
| Aboh33 wrote:
| I recently found there was a clojure implementation for .NET and
| also one for the BEAM Virtual Machine. Has anyone used the
| latter? Regards
|
| [1] https://github.com/clojure/clojure-clr [2]
| https://github.com/clojerl/clojerl
| AkshitGarg wrote:
| There is also lfe [1] which is a lisp for the BEAM VM
|
| [1] https://lfe.io/
| segeda wrote:
| And also https://github.com/clojerl/clojerl
| zcam wrote:
| There is also ClojureDart in the making. That one seems quite
| promising.
| didibus wrote:
| Why do you say "was"? They are both still actively developed
| even if not very popular.
| tobyhinloopen wrote:
| Using dashes in function names? Blasphemy
| sandbags wrote:
| Funky, I hadn't even noticed I had switched back when I started
| thinking about Clojure and that it's not legal Elixir. I had to
| go check my Elixir code to find the _'s!
| nlitened wrote:
| That's called "kebab case". When your language supports it, you
| know the language is good :)
| dnautics wrote:
| You can, you can match against the module in the struct of the
| second parameter, concatenate the two modules, and manually
| dispatch against the concatenated module. I don't really
| recommend this (it is not performant and feels like a code
| smell), but it is possible
| blunte wrote:
| Does performance matter considering Elixir is already very slow
| in per-thread performance?
| brightball wrote:
| How is it slow?
| blunte wrote:
| How? Do you mean how do I know it's slow? Because it takes
| longer to run.
|
| Write a typical computation such as Fibonacci in Java and
| Erlang/Elixir and compare. Fortunately someone has already
| done this.
|
| Elixir is 3x slower than C and 2x slower than Java for this
| single thread example.
|
| https://github.com/drujensen/fib
|
| Apparently this upsets people for me to point this out.
| However, I did not say that Elixir was slow in general or a
| bad choice. It's an excellent choice for problems which
| suit parallelization or which require reliable, consistent
| performance.
|
| Since the parent poster had commented that adding this
| multi-module dispatch would not be performant, I merely
| pointed out that the single thread peformance was already
| slow (as in, why worry too much about the performance cost
| of the multi dispatch suggestion).
| CraigJPerry wrote:
| I'm starting to get a bit fed up with the down-voting
| behaviour here recently.
|
| It used to be that on HN you down-voted for people who
| were obstructing conversation, being disingenuous or in
| some cases being excessively disrespectful.
|
| Now having read 3 of your comments and seeing all 3 are
| heavily down-voted and yet the content of your messages
| is constructive and interesting.
|
| If you disagree with something, fine, just don't vote on
| it. Save the down-votes for bad actors, not someone with
| a different view.
|
| The last thing HN needs is to become the kind of place
| where you're actively encouraged to karma farm or
| whatever that term is for that behaviour on reddit.
| ddek wrote:
| Eh, I'd rather the thread discussed the language features
| in TFA. Once again, a potentially interesting comment
| section is sidetracked by _yet another referendum_ on {{
| niche_programming_language }} 's application to web
| development. Can't we just keep this to release posts?
| dnautics wrote:
| I think they were downvoted because the first response
| was almost contentless and the other posts complain too
| much about the downvotes. Yes, there is some "good info"
| there but basically they are still presented in a
| relatively context-poor fashion and defensive, and
| willfully ignoring other points being made, and most
| active practitioners of elixir are aware of the context,
| so the comments are of questionable utility except for
| people who don't use the system, who may interpret it out
| of context and come to conclusions that are wrong. In
| short, they _still_ have a shitposty feel.
| brightball wrote:
| It's slower for an operation like that because of the
| scheduler ensuring a single process isn't hogging all of
| the CPU.
|
| When was the last time you needed to write a Fibonacci
| for anything you've built in your career?
|
| It's a benchmark that doesn't show anything useful for
| real world applicability.
| dnautics wrote:
| depends on what you are doing. And it's not necessarily "very
| slow", moving forward as the JIT gets better and better. I
| highly doubt that this technique is going to be very
| jittable.
| Zababa wrote:
| On the web site of things, it is faster than Rails, Django,
| Laravel, Express and even Spring, and this is with Plug and
| Ecto. https://www.techempower.com/benchmarks/. That seems to
| be very good performance to me.
| blunte wrote:
| People go nuts here on HN if they think you said something
| bad about their baby.
|
| I said per-thread, but I meant single-thread... as in CPU
| bound single process activity. That is undisputedly slow
| compared to languages like Java, C/C++, Go, etc. That is
| also very much not what Erlang is designed for. It adds a
| lot of overhead with the supervisor and other features
| which do not give a benefit for single thread CPU heavy
| activities.
|
| And since the parent poster mentioned the multi-dispatch
| approach would not be performant, I attempted to suggest
| that the performance cost of that would be less relevant
| considering Elixir is already not very performant in single
| thread cases. In other words, it was a moot point.
|
| I never said that Elixir/Erlang was slow for multi-
| thread/process distributed activities. Obviously that is
| where it really excels. But if you want to crunch numbers
| sequentially in a way that cannot be spread across multiple
| processes/threads, then you will find Elixir to be slow.
|
| The benchmarks you are referring to are very much multi-
| thread comparisons. They are specifically NOT what I was
| was slow.
| Zababa wrote:
| You're right about the performance of single-threaded vs
| multi-threaded Elixir. However, I used web apps as a
| comparison because they are the most common use case for
| Elixir. Considering here Elixir performs very well,
| performance could be one of the reasons why people choose
| it. In that case, being aware of performance pitfalls is
| a good thing.
|
| I don't agree that performance is a moot point if what
| you use is slower than some alternatives, and I think
| that's the main point where we disagree.
| blunte wrote:
| I am not a fan of slowing something down, but in the
| multi-method dispatch example, unless it was being
| exercised in a tight loop (which would seem very much
| like a single thread CPU bound scenario which is already
| a problem), then it wouldn't be exercised often enough to
| make a big impact. That's just my gut feeling based on my
| experiences.
|
| But if this really is a big deal, then it would be fair
| to consider the other language features which do not
| contribute to the reliability, scalability, and other
| core Erlang/BEAM features. For example, what is the cost
| of pattern matching in general? Doesn't that add
| considerable overhead, just for the benefit of making
| code cleaner? If that's acceptable, then I don't see why
| "just one more" feature - in this case a homegrown multi-
| method dispatch across modules - should be considered
| non-performant.
| ch4s3 wrote:
| Pattern matches should execute in linear time in the
| worst case worst. Generally you want to place the most
| likely and specific matches first.
| Zababa wrote:
| Good point about the tight loop. For the other part, my
| gut feeling would be that there is a "base language" that
| most developers are familiar with, and accept the
| performance/other things tradeoffs of, but for more
| obscure features, people are explicit about these points
| because they are less known.
| dnautics wrote:
| defmodule A do defstruct [...] end
| defmodule B do defstruct [...] end
| defprotocol C do def foo(a, b) end
| defimpl C, for: Any do def foo(x1 = %m1{}, x2 =
| %m2{}) Module.concat(m1, m2).foo(x1, x2)
| end end defmodule A.A do def foo...
| end defmodule A.B do def foo...
| sandbags wrote:
| Ah, this is very neat.
| dnautics wrote:
| yep. pattern matching on the `__struct__` sugar, the poor
| man's protocol!
| tekacs wrote:
| > Now Elixir has an equivalent to multi, the Protocol.
|
| For what it's worth, Clojure also has a much closer fit to Elixir
| Protocols called... a Protocol.
|
| https://www.braveclojure.com/multimethods-records-protocols/...
|
| They too can only dispatch on the type of the first argument, but
| are more structured (you can add multiple pieces of behavior at a
| time) and performant than multimethods where that's the behavior
| you're looking for.
| didibus wrote:
| Elixir's Protocols actually were inspired by Clojure Protocols.
|
| Here's Jose Valim talking about it:
|
| > I've learned a lot also from Clojure because, at the time I
| was thinking about Elixir, Clojure was already around. I like
| to say it's one of the top three influences in Elixir
|
| [...]
|
| > The main, the top three influences are Erlang, Ruby, and
| Clojure.
|
| [...]
|
| > I was like, no, but I'm going to call them protocols because
| there are a lot of similarities between Clojure and Elixir in
| terms of them being dynamic languages and in terms of the macro
| system. I was like, okay, I'm going to call them protocols
| because the closest thing we have today to what I want is
| Clojure
|
| And he goes on talking about more inspiration and similarities
| from Clojure like Agents, etc.
|
| Full exert is here: http://blog.cognitect.com/cognicast/120
| tekacs wrote:
| I'll also leave these here, in case the conversation inevitably
| turns to pattern-matched function definition in Elixir. :)
|
| https://github.com/clojure/core.match -- pattern matching as a
| library
|
| https://github.com/killme2008/defun -- using core.match to
| implement Elixir/Erlang-like function definition
|
| https://github.com/noprompt/meander -- advanced pattern
| matching, for some fun and flavor :)
|
| What's also fun is that core.match is implemented using a paper
| from INRIA on how to efficiently convert patterns into decision
| trees:
|
| https://github.com/clojure/core.match/wiki/Understanding-the...
| jwhitlark wrote:
| I've always loved that paper. Very readable, and gives good
| insights.
| SatvikBeri wrote:
| If videos are more your speed, David Nolen, the primary
| author of that library (and article) has a talk about it as
| well: https://www.youtube.com/watch?v=TVJa-V6U-XI
| ollysb wrote:
| https://github.com/OvermindDL1/protocol_ex gives you protocols
| with full pattern matching.
| sandbags wrote:
| Brilliant, thank you.
|
| I assumed that, with Elixir macro support, someone could
| implement protocols with full pattern matching. Just way above
| my current pay grade!
| dmitriid wrote:
| It's one of those "rarely used in practice but insanely
| frustrating when you write a library or some generalized code".
|
| However, I'd rather Clojure got proper pattern-matching than
| Elixir multimethods. I find pattern matching a much more
| powerful, flexible and useful tool.
| OliverM wrote:
| Why not just use core.match?
| https://github.com/clojure/core.match
| rainygold wrote:
| Feels like Elixir has stolen much of Clojure's appeal and
| 'thunder' as the niche pragmatic functional language.
| arvidkahl wrote:
| The ruby-like syntax and the VERY open and newbie-friendly
| community have definitely contributed to this.
|
| I've been to Elixir conferences, and they felt like people were
| just encouraging each other to build solid software WITH each
| other. I've not seen this level of camaraderie for other
| programming language communities.
|
| Elixir devs -- and I am super biased here -- are a special
| bunch :)
| uDontKnowMe wrote:
| That's great to hear! I get the same feeling towards the
| Clojure community as well, some of the friendliest, smartest
| and most helpful people hanging out at the Clojure watering
| holes (in comparison to other languages I've worked with). I
| also am constantly in awe of the output of the Clojure world.
| There are like 3 or 4 great podcasts going, so many cool
| projects being worked on, especially for a community which
| seems to be sadly so small.
| filoeleven wrote:
| Which podcasts do you recommend?
| uDontKnowMe wrote:
| I like:
|
| Defn: https://podtail.com/en/podcast/defn/
|
| The REPL: https://www.therepl.net/episodes/ (Seems to
| have gone quiet)
|
| ClojureScript Podcast: https://clojurescriptpodcast.com/
|
| Functional Design in Clojure: https://clojuredesign.club/
| (Also seems to have gone quiet since December)
|
| LispCast by Eric Normand: https://lispcast.com/
|
| Cognitect, the company behind Clojure also has their own
| podcast but I haven't found it to be that interesting
| most of the time, at least yet:
| https://www.cognitect.com/cognicast/index.html
|
| Not specifically Clojure-related but has discussed a few
| times including wit Rich Hickey (as well as other
| unrelated great conversations!): CaSe https://www.case-
| podcast.org/
|
| Completely not at all about Clojure but great software
| podcasts:
|
| Go Time: Even though I hardly ever write Go, I find their
| conversations to be really great and having lessons
| beyond Go. It helps that I am interested in the language
| though: https://changelog.com/gotime
|
| Web Development and Development in general - The Bike
| Shed: https://www.bikeshed.fm/
|
| Software Engineering Radio: https://www.se-radio.net/
|
| CoRecursive: https://corecursive.com/
|
| Inside Java: https://inside.java/
| rainygold wrote:
| Community can definitely play a role though I can't help but
| think that Phoenix and the proselytizing done by Jose and co
| are the main factors.
|
| Sure, we have Luminus in the Clojureverse but its just not as
| easy and straightforward as the Rails-like experience of
| Phoenix. You don't have Hickey personally responding to
| comments on HN/Reddit etc.
| KingMob wrote:
| Hickey is extremely remote from the Clojure community. Most
| of Cognitect is. Really, only Alex Miller engages on a
| regular basis. To a lesser extent, Fogus and Ghadi do, too.
|
| The Clojurescript community is friendlier, IMO.
| rainygold wrote:
| Much to the detriment of the language imo, and he didn't
| help the feeling when he released 'Open Source is not
| about you'
| uDontKnowMe wrote:
| I would agree here that the combination of being "closed
| to collaboration", the slow pace of development lately,
| and really infrequent communication from the sole
| owner/leader/BDFL does send a weird vibe and raises some
| concern regarding what direction the language is going to
| be going in in the future.
| jshen wrote:
| Isn't one of the beauties of lisp is that you don't need
| much from the language creator. It should be far more
| stable than non-lisp languages, and you can implement
| most ideas with macros outside of the core language.
| uDontKnowMe wrote:
| You can get a pretty long way but there are still things
| that need to be improved over time. For example Clojure
| still 7 years after the java 8 release doesn't have great
| integration with java 8 functional interfaces, which is a
| pretty big detriment to java interop. I saw this patch
| which seems to have been submitted by a community member
| https://clojure.atlassian.net/browse/CLJ-2637 (not sure
| if the author is a core contributor or what), but even
| after month no comment from Rich or anyone else on the
| team to indicate if this is a good idea, if they'd let it
| in or what.
| didibus wrote:
| For the most part, Clojure is tuned for experienced
| developers I think. It's kind of an oximoron, but it feels
| like it was Rich Hickey's goal as well, to not appeal to
| any of the "easy" and "convenient" and "familiar", but
| focus entirely in "no bs", "simple" and "very flexible"
| pieces that never break backwards compatibility, are always
| open for extension, keep performance in mind, reaches for
| battle tested hosts when it can, and all that.
| didibus wrote:
| There's a big downside to Clojure having the most amount of
| experienced developers I think in bringing beginners in.
| You'd think it be the opposite, but beginners are better
| treated by other passionate smart beginners and people who
| just got out of being a beginner. As experienced old devs
| tend to not have the time or patience or not know how to
| explain things or make it beginner friendly.
| brianberns wrote:
| To me, F# is the pragmatic functional language with the most
| appeal, but being on .NET maybe it's not even niche.
| sandbags wrote:
| Honestly I wouldn't be using Elixir if it wasn't for my co-
| founder's singing the praises of Phoenix & Liveview. I'd tried
| it once about a year ago but couldn't see any advantage over
| Clojure (esp. with re-frame). Sadly he was never going to move
| to Clojure.
|
| That said, now I've dug in and really used it for solving some
| problems I am finding it an elegant and enjoyable experience.
|
| I'd happily use either although I think Elixir has a particular
| fit to web applications.
| dgb23 wrote:
| Elixir seems to be very approachable. But some of the strengths
| of Clojure are unmatched, such as Java/JS interop, isomorphic
| code for web development, and generally being a Lisp (which
| includes macros).
| Zababa wrote:
| Elixir has macros. People are currently building Nx
| https://github.com/elixir-nx/nx while not having to change
| anything in the language. Java/JS interop being unmatched is
| true, but Elixir has Erlang interop too.
| rainygold wrote:
| LiveView sorta tackles the isomorphic web development side,
| and while I agree that Lisp is a better syntax you do have
| hygienic macros in Elixir as well.
| lawn wrote:
| Elixir has macros too.
| nesarkvechnep wrote:
| Elixir has Erlang interop. Erlang is a 30 year old language.
| adamkittelson wrote:
| Yes and no. Yeah Erlang has been around for 30 years but
| "30 year old language" makes it sound like it came out 30
| years ago and then stopped. Erlang is still being very
| actively developed and improved, it's by no means a crusty
| old language.
| prophesi wrote:
| I'm not sure what the implications are of either comment.
| Both Java and Javascript are reaching the 30 year old
| mark as well.
| vendiddy wrote:
| Elixir afaik has taken a lot of inspiration from clojure and
| lisp type languages.
|
| It's not readily apparent from the ruby like syntax though.
| kopos wrote:
| 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.
| jeremyjh wrote:
| > 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?
| divs1210 wrote:
| 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.
| tomjakubowski wrote:
| 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
| divs1210 wrote:
| 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))
| jeremyjh wrote:
| 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.
| sergiomattei wrote:
| 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
| ...
| brightball wrote:
| This was one of my big impressions of Elixir. It forces you
| into so many things that improve long term maintainability.
| winrid wrote:
| 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.
| elcritch wrote:
| 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.
| divs1210 wrote:
| 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".
| IggleSniggle wrote:
| 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.
| sandbags wrote:
| 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.
___________________________________________________________________
(page generated 2021-07-17 23:01 UTC)