Tracks
/
Elixir
Elixir
/
Temario
/
Protocolos
Pr

Protocolos en Elixir

4 ejercicios

Acerca de Protocolos

Los protocolos son:

  • Un mecanismo para lograr polimorfismo.
  • Se definen con defprotocol.
  • Se implementan para un tipo de dato específico con defimpl.

Una gran fortaleza de los protocolos es que la implementación de un protocolo para un tipo de dato específico no necesita venir junto con la definición de ese tipo de dato ni con la definición del protocolo. Esto permite escribir bibliotecas que sus usuarios pueden extender fácilmente para que funcionen con los tipos de datos personalizados de esos usuarios, sin tener que modificar la biblioteca.

Implementación

Es posible implementar protocolos para todos los tipos de Elixir: Tuple, Atom, List, BitString, Integer, Float, Function, PID, Map, Port, Reference, Any y los structs.

Los protocolos se pueden implementar para varios tipos a la vez:

defimpl Reversible, for: [Map, List] do
  def reverse(term) do
    Enum.reverse(term)
  end
end

Cuando implementas un protocolo para un struct directamente dentro de un módulo que define ese struct, puedes omitir el argumento :for:

defmodule ShoppingCart do
  defstruct [:items]

  defimpl Reversible do
    def reverse(shopping_cart) do
      Enum.reverse(shopping_cart)
    end
  end
end

Respaldo con Any

De forma predeterminada, invocar un protocolo para un tipo de dato que no lo implementa lanzará un error Protocol.UndefinedError:

to_string({})
# => ** (Protocol.UndefinedError) protocol String.Chars not implemented for {} of type Tuple
#        (elixir 1.10.3) lib/string/chars.ex:3: String.Chars.impl_for!/1
#        (elixir 1.10.3) lib/string/chars.ex:22: String.Chars.to_string/1

Es posible evitar eso si proporcionas una implementación de respaldo que se use en un caso así. Para hacerlo, asigna true al atributo de módulo @fallback_to_any cuando definas el protocolo y escribe una implementación para el tipo Any:

defprotocol Reversible do
  @fallback_to_any true
  def reverse(term)
end

defimpl Reversible, for: Any do
  def reverse(term) do
    term
  end
end

Ten en cuenta que en la mayoría de los casos lo preferible es lanzar un error, porque es difícil hacer una suposición razonable sobre un protocolo para todos los tipos de datos.

Protocolos integrados que vale la pena conocer

  • Enumerable: las funciones de los módulos Enum y Stream funcionan con los tipos de datos que implementan este protocolo.
  • Collectable: la función Enum.into/2 usa este protocolo para insertar un enumerable dentro de una colección.
  • Inspect: puedes implementar este protocolo para cambiar la forma en que Kernel.inspect/2 representa un tipo de dato específico como un string.
  • String.Chars: puedes implementar este protocolo para cambiar la forma en que Kernel.to_string/1 representa un tipo de dato específico como un string.
Editar en GitHub El enlace se abre en una ventana o pestaña nueva

Aprende Protocolos

La práctica está bloqueada

Desbloquea 1 ejercicio más para practicar Protocolos