Methods in Elixir

In Elixir, we can define modules and functions to create similar behavior to structs and methods in other languages. Here’s how we can implement the rectangle example:

defmodule Rect do
  defstruct width: 0, height: 0

  def area(%Rect{width: w, height: h}) do
    w * h
  end

  def perim(%Rect{width: w, height: h}) do
    2 * w + 2 * h
  end
end

defmodule Main do
  def run do
    r = %Rect{width: 10, height: 5}

    # Here we call the 2 functions defined for our struct.
    IO.puts("area: #{Rect.area(r)}")
    IO.puts("perim: #{Rect.perim(r)}")

    # In Elixir, all data is immutable, so there's no distinction
    # between passing a struct or a reference to it.
    # The following calls will produce the same result.
    IO.puts("area: #{Rect.area(r)}")
    IO.puts("perim: #{Rect.perim(r)}")
  end
end

Main.run()

In this Elixir code:

  1. We define a Rect module that includes a struct definition with width and height fields.

  2. The area and perim functions are defined within the Rect module. These functions use pattern matching to extract the width and height from the Rect struct.

  3. In the Main module, we create an instance of Rect and call the area and perim functions.

  4. Elixir doesn’t have the concept of pointers or references like some other languages. All data in Elixir is immutable, so there’s no need to distinguish between value and reference semantics.

To run this program, save it in a file (e.g., rect.exs) and execute it using the elixir command:

$ elixir rect.exs
area: 50
perim: 30
area: 50
perim: 30

This Elixir implementation showcases how we can achieve similar functionality to methods in other languages using modules and functions. The pattern matching in function definitions provides a clean way to work with structured data.

Next, we’ll look at Elixir’s mechanism for defining interfaces and protocols, which provide a way to implement polymorphic behavior across different data types.