GPrimola

GPrimola

Using defprotocol with defstruct for "data inheritance"

Hey guys,

I was trying Protocols and I saw a possibility I’ve never saw before, the use of defprotocol with defstruct.
I haven’t gone too much further on the implications, but the code below works fine.

defprotocol Foo do
  defstruct [:bar]
  def bar(foo)    
end

defimpl Foo, for: Foo do
  def bar(foo), do: foo.bar
end

defprotocol Zoo do
  defstruct [:foo, :some]
end

defimpl Foo, for: Zoo do
  def bar(zoo), do: zoo.foo.bar
end

With the code above we can notice that the Foo protocol will also behave like a module, i.e., the functions can have a body.

This “pattern” could be useful for data inheritance/composition where we have an is relationship, like for instance when we have a case where Person “is a” User and Employee “is a” Person, and both Employee and Person structs would “inherit” (sorry the OO term) User’s attributes.

So, by using Protocols we could do:

defprotocol User do
  defstruct [:username, :password]

  def get_username(user)
end

defprotocol Person do
  defstruct [:user, :name, :age, :birth_date]

  def to_str(person)
end

# Here I could've also modeled Employee using defprotocol too
defmodule Employee do
  defstruct [:person, :wage, :department]
end

defimpl User, for: Person do
  def get_username(person), do: person.user.username
end

defimpl User, for: Employee do
  def get_username(employee), do: employee.person.user.username
end

defimpl Person, for: Employee do
  def to_str(employee) do
    "#{employee.person.name} #{employee.person.age} @ #{employee.department}"
  end
end

To be used like this:

iex(21)> employee = %Employee{person: %Person{user: %User{username: "gio"}, name: "Giorgio", age: "30+"}, department: "IT"}

iex(22)> User.get_username employee
"gio"
iex(23)> Person.to_str employee
"Giorgio 30+ @ IT"

My question is if Protocols were designed to be used this way too?

First Post!

Sebb

Sebb

From the guide:

dispatching on a protocol is available to any data type that has implemented the protocol

That is not true for your protocol. Only data types that have a specific shape would work.

Where Next?

Popular in Questions Top

bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
makeitrein
Hey all, just started picking up Elixir last week and am writing a scraper as a learning project. Baby step #1 is extracting the number ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> someth...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

Other popular topics Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

We're in Beta

About us Mission Statement