Invocación de funciones dentro del mismo módulo

Algunas puntualizaciones sobre llamadas a funciones pertenecientes al mismo módulo, y uso de defp para crear funciones que sólo pueden ser invocadas desde dentro del mismo módulo.

En Elixir, una práctica fundamental para mantener nuestro código limpio y manejable es dividir las tareas complejas en funciones pequeñas y específicas. Ya sabemos que podemos llamar funciones de otros módulos, como IO.puts, pero también es muy común y útil llamar funciones dentro del mismo módulo. Esto nos permite organizar mejor nuestro código y facilitar su comprensión.

Cuando una función empieza a crecer en líneas o en complejidad, lo ideal es extraer partes de esa lógica en funciones auxiliares. Así, cada función hace una cosa concreta y podemos entenderlas por separado sin perdernos en un bloque de código demasiado extenso. Esto es especialmente importante en Elixir, donde cada función es una expresión y podemos componerlas para construir funcionalidades más complejas.

Para ilustrar esta idea, podemos crear un módulo llamado Impuestos que calcule el impuesto a pagar según el tipo de producto. En España, por ejemplo, existen tres tipos de IVA: normal, reducido y superreducido, que aplican diferentes porcentajes. En lugar de poner estos porcentajes directamente en la función principal, creamos una función de apoyo que, dado un tipo, devuelve el porcentaje correspondiente.

Podemos implementar esta función porcentaje usando un condicional cond que evalúe el tipo y devuelva el valor adecuado:

defmodule Impuestos do
  def impuesto(precio, tipo) do
    precio * porcentaje(tipo)
  end

  defp porcentaje(tipo) do
    cond do
      tipo == :normal -> 0.21
      tipo == :reducido -> 0.10
      tipo == :superreducido -> 0.04
    end
  end
end

Aquí, impuesto/2 calcula el impuesto multiplicando el precio por el porcentaje que devuelve porcentaje/1. Notemos que porcentaje está definida como una función privada con defp, lo que significa que solo puede ser llamada desde dentro del módulo Impuestos. Esto es importante para encapsular la lógica interna y evitar que otras partes del programa usen funciones que no deberían ser accesibles directamente.

Además, Elixir nos facilita la llamada a funciones dentro del mismo módulo sin necesidad de anteponer el nombre del módulo. Por ejemplo, dentro de impuesto/2 podemos llamar simplemente a porcentaje(tipo) en lugar de Impuestos.porcentaje(tipo). Esto hace que el código sea más limpio y legible.

Si intentamos llamar a Impuestos.porcentaje(:normal) desde fuera del módulo, obtendremos un error porque porcentaje es privada. En cambio, podemos llamar a Impuestos.impuesto(10, :reducido) y obtener el cálculo correcto del impuesto para un precio de 10 con tipo reducido.

Esta forma de organizar el código nos permite tener funciones pequeñas, claras y bien agrupadas. Las funciones privadas actúan como piezas internas que solo el módulo conoce y utiliza, mientras que las funciones públicas son la interfaz que exponemos para que otros módulos o partes del programa interactúen con nuestro código.

En definitiva, separar la lógica en funciones privadas de apoyo nos ayuda a escribir código más estable, fácil de mantener y entender. Así evitamos tener funciones largas y complejas, y podemos modificar detalles internos sin afectar la interfaz pública del módulo. Esta modularidad es clave para desarrollar aplicaciones Elixir robustas y limpias.

Lista de reproducción
  1. 1
    ¿Qué es Elixir?
    10 minutos
  2. 2
    Instalación de Elixir
    9 minutos
  3. 3
    ¿Qué es la programación funcional? (Como la de Elixir)
    20 minutos
  4. 4
    ¿Cómo funciona la REPL de Elixir?
    7 minutos
  5. 5
    ¿Cómo hacer asignaciones en Elixir?
    7 minutos
  6. 6
    Operadores aritméticos básicos
    6 minutos
  7. 7
    ¿Qué son los tipos de datos de Elixir?
    5 minutos
  8. 8
    Átomos en Elixir
    4 minutos
  9. 9
    Las palabras clave nil, true y false
    6 minutos
  10. 10
    Operadores lógicos de comparación
    8 minutos
  11. 11
    Comparación estricta con ===
    3 minutos
  12. 12
    Operadores lógicos y proposicionales
    8 minutos
  13. 13
    Invocación de funciones
    10 minutos
  14. 14
    Fundamentos de funciones
    9 minutos
  15. 15
    Cadenas de caracteres
    8 minutos
  16. 16
    Entrada y salida estandar de la mano de gets y puts
    9 minutos
  17. 17
    Concatenar e interpolar strings
    9 minutos
  18. 18
    Código fuente en archivos
    9 minutos
  19. 19
    Condicional IF y bloques DO-END
    11 minutos
  20. 20
    IFs anidados, UNLESS y COND
    12 minutos
  21. 21
    Definición de funciones
    11 minutos
  22. 22
    Fundamentos de compilación de módulos
    6 minutos
  23. 23
    Guardas
    8 minutos
  24. 24
    Funciones anónimas
    7 minutos
  25. 25
    Capturar funciones
    4 minutos
  26. 26
    Invocación de funciones dentro del mismo módulo
    7 minutos
  27. 27
    Tuplas
    8 minutos
  28. 28
    Introducción al pattern matching
    8 minutos
  29. 29
    Pattern matching en funciones
    11 minutos
  30. 30
    Las tuplas :ok, :error
    7 minutos
  31. 31
    case
    10 minutos
  32. 32
    Operador pin
    7 minutos
  33. 33
    Pattern matchings y recursividad
    5 minutos
  34. 34
    Listas
    9 minutos
  35. 35
    Operadores y funciones de lista
    10 minutos
  36. 36
    Keyword lists: listas de palabras clave
    8 minutos
  37. 37
    Mapas
    7 minutos
  38. 38
    Pattern matching de mapas y keyword lists
    6 minutos
  39. 39
    Operadores y funciones para mapas y keyword lists
    5 minutos
  40. 40
    Estructuras con defstruct
    11 minutos
  41. 41
    Bitstrings
    11 minutos
  42. 42
    Charlists
    10 minutos
  43. 43
    Funciones de alto orden en Elixir
    5 minutos
  44. 44
    Uso de la función filter
    10 minutos
  45. 45
    Uso de la función map
    7 minutos
  46. 46
    Uso de la función reduce
    9 minutos
  47. 47
    Pipelines
    11 minutos
  48. 48
    Rangos y Streams
    11 minutos
  49. 49
    Funciones recursivas con listas
    14 minutos