JKWA
Author of Advanced Functional Programming with Elixir
Polymorphism in Elixir
I didn’t have room for this in my book, Advanced Functional Programming with Elixir , but I still thought it was worth sharing on my blog.
Trending in Blog Posts
Hey folks,
I just published a post about Hologram’s funding and where the project goes next - the short version:
Curiosum as Main Spons...
New
Hi all,
In this article, I make the case for each test owning its setup.
Usually I forbid my AI agents to use the setup callbacks; I mu...
New
As I’ve leaned into AI code generation on LocalCents, the volume I ship has climbed, and my worry shifted from any single change to the l...
New
I wrote about an issue I had with a LiveView application, and how I solved the problem by debouncing updates server-side (within the Live...
New
I’ve published a new article in my Elixir learning series on dev.to exploring what happens when tagged tuples aren’t enough - the try, re...
New
This article demonstrates how to build a minimal stateful process using only Elixir’s core concurrency primitives: spawn/1, send/2, recei...
New
A recent ex_money v6 upgrade was blocked because Timex pins an old gettext. Rather than one big remove-and-rewrite PR, I used a shim: a m...
New
Other Trending Topics
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve.
They are GUI (Emerge) and State management (S...
New
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #performance











First 10 of 14 Posts
adamu
These two statements contradict each other, perhaps the footer on the blog is generic and doesn’t apply in this case?
I think behaviours also deserve a mention along with protocols. My experience is that it’s quite rare to write a protocol, compared to a behaviour.
For example,
Eqcould also be implemented using a behaviour:krasenyp
I really don’t know why there’s this behaviour fetish in the community. Protocols are for polymorphism. You use the protocol more or less directly. With behaviours you fill holes by providing callbacks. There is a framework, like the GenServer, which calls the module which implements the callbacks.
LostKobrakai
I’m not sure I see the point in a polymorphic
equal?in the first place. One of the usecases for (dynamic) polymorphism is that the interface can exist independently from the implementations and implementations can independently maintained. Comparingatobis not a problem well suited to that if any ofaorbare of arbitrary type, because both types need to interact to be compared, hence they’re no longer independent.Elixir actually kinda has a polymophic option in that domain:
Enum.sortcan receive a module to do the comparison between items in order to sort elements of a list. It’s not officially a behaviour, but uses the single@callback compare(a, b) :: :lt | :eq | :gt. The big difference on that one – it’s not polymorphism on a per type level. Each passed module needs to be able to deal with all elements it gets thrown at for comparison and you won’t be able to later bring in a new struct and make it be handled differently.JKWA
Good point on the contradictory phrasing, I trimmed these kinds of language-specific details from the book after some early feedback. The footer is just a standard note pointing readers toward the book if they want more depth, though it does not always apply perfectly.
I agree behaviours are important, but I would not say they implement polymorphism. They enforce a contract, but you still have to choose which module to call. To me, polymorphism means a function changes behavior based on the type of input, which is the protocol.
sodapopcan
I’ve found myself deriving protocols a lot to sort of mimick Rails’ “concerns” (but in a functional way) and I’m wondering if it is the optimal way.
This is a simple example that for associating a note with any other record. I do add a direct fkey to the notes table for everything it can be assoicated with (avoiding the
noteable_typeandnoteable_idpattern from other frameworks) but otherwise this mainly DRYs up having to mention these anywhere else (pattern matching to dispatch and typespecs mainly).Here’s a stripped-down example:
I wanted to key the sample small but there is also a
assoc_keyon the protocol which allow finding a note so we do:Again, I’ve been wondering about the general utility of this. We have a few of these things that all operate similarly so the abstraction feels worth it, but I’ve been wondering if I’m overlooking a simpler way (that is, outside of not using any abstraction at all).
Another I’ve seen stuff like this done in the past would be using macros to add
list_notesto all contexts that have notes. I’ve found this can cause some nasty compile time deps and still requires setting up the schema stuff.Anyway, I hope this is on topic
JKWA
Yes, we’re both solving the same problem: defining a default comparison for a type.
Here’s how I might implement the homogeneous
sort:This lets the caller sort a list using the domain’s default ordering or pass in a different
Ordwhen needed. It supports cases where the same type needs multiple comparison strategies. It also allowsOrdcomposition, making it easy to build more complex ordering logic.JKWA
I admit, I’m having a bit of trouble giving helpful advice on this one.
Your goal, as I understand it, is to reduce Ecto boilerplate, and you’re also, in a sense, extending Ecto’s macro system. Within your project, I don’t see a problem, except that it introduces a bit of indirection that you’ll need to make sure your colleagues understand.
From the perspective of protocols, what hung me up is that I was looking for the polymorphism problem you were solving, but in the end, I think you’re using the protocol more as a contract.
Is this generalizable? I see some tight coupling to your domain, so my answer would be probably not, but I might be misunderstanding.
Is there another way to solve it? Sure. But you’re approaching it from a Ruby context, and I don’t have enough Ruby experience to say whether there’s a better alternative through that lens.
dimitarvp
That’s basically why I don’t want to use protocols and I am resisting them in work places. To me they are kind of implicit. A behaviour is an explicit function argument. I am tired of magic.
JKWA
Oh, interesting. You’re seeing magic where I’m seeing decoupling. I suppose it comes down to perspective.
sodapopcan
Thanks for your reply!
Ruby’s “concern” concept is no more than a wrapper around mixins/traits, so it’s not really a Ruby specific thing but a general OO one. I guess I’ve never felt super confident of how to tackle things in Ecto that I would have used mixins/traits for in OO. Protocols always seemed the best fit. It essentially creates the classic “basic” difference between method and function calls:
and
Yes that’s really all it is. My thing is actually really an even more general abstraction around dynamically resolving an Ecto association. We have a bunch of these things and it ends up with a bunch of copy/paste code or being implemented slightly differently, so to me learning a tiny bit of reflection once is better than the inevitable inconsistencies that come about. YMMV, of course.