angelmz

angelmz

Wanting to know more about the "Elixir" way of doing things

I’m still fairly new to the language. I wanted to know more about the “Elixir” way of doing things so I wrote a tiny program 3 ways, but I’m not sure which is the “right way”. I know you’d normally want only one module per page, this is just for demonstration purposes.

This one has the most isoloation of responsibilities:

defmodule Shapes do
  defmodule Rectangle do
    defstruct [:width, :height]

    def perimeter(%Rectangle{width: width, height: height}) do
      2 * (width + height)
    end

    def area(%Rectangle{width: width, height: height}) do
      width * height
    end
  end

  defmodule Circle do
    defstruct [:radius]

    def area(%Circle{radius: radius}) do
      radius * radius * :math.pi()
    end
  end
end

This one leverages pattern matching a little more.

defmodule Shape do
  defmodule Rectangle do
    defstruct [:width, :height]
  end

  defmodule Circle do
    defstruct [:radius]
  end

  def perimeter(%Rectangle{width: width, height: height}) do
    2 * (width + height)
  end

  def area(%Rectangle{width: width, height: height}) do
    width * height
  end

  def area(%Circle{radius: radius}) do
    radius * radius * :math.pi()
  end
end

This is my attempt at implementing it as a protocol. I’m a little unsure
because to my understanding protocols are for taking in different types.

defprotocol Shape do
  def area(data)
  def perimeter(data)
end

defmodule Rectangle do
  defstruct [:width, :height]

  defimpl Shape, for: Rectangle do
    def area(%Rectangle{width: width, height: height}) do
      width * height
    end

    def perimeter(%Rectangle{width: width, height: height}) do
      2 * (width + height)
    end
  end
end

defmodule Circle do
  defstruct [:radius]

  defimpl Shape, for: Circle do
    def area(%Circle{radius: radius}) do
      :math.pi() * radius * radius
    end
  end
end

Thank you for any help :slight_smile:

Marked As Solved

gregvaughn

gregvaughn

This sample project is almost a textbook example of polymorphism. Protocols are Elixir’s core way of supporting polymorphism. That being said, your second approach is not bad when you have limited expectations of the datatypes to support.

The main thing a protocol offers over the second approach is that you could publish the Protocol in one package. Then some other library author could choose to make their new data structure (which was unknown to you when you wrote the Protocol) fit into it.

Also Liked

ityonemo

ityonemo

You don’t need the for: when the defimpl is nested in the module it’s implementing for.

If this were actually intended to be reused I would also maybe make your modules be Shape.Rectangle and Shape.Circle to avoid module name piracy (keep as many top level namespaces open, we have aliases to help readability)

LostKobrakai

LostKobrakai

This is special though. All the “optional” callbacks of Enumerable can be implemented using the non optional reduce/3. The optional ones are only useful when the underlying datastructures allow for more efficient ways for those operations than using reduce/3. So you can still use Enum.count on any Enumerable, even if the implementation returns {:error, __MODULE__}.

That’s different to not implementing part of a protocol.

Also I think @optional_callbacks is the more appropriate way to mark optional callbacks, but Enumerable likely can’t do so for historical reasons.

Where Next?

Popular in Questions Top

beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> somethi...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
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
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
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New

Other popular topics Top

axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 48342 226
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
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43757 214
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
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement