Pequeños detalles sobre los átomos en Erlang

La semana pasada empecé a publicar mi curso de Elixir en YouTube, y la recepción está siendo buena e incluso algo mejor de lo esperado. Intento ir lento para ponerlo fácil a quien nunca haya trabajado con este tipo de lenguajes, pero a la vez intento ir rápido para satisfacer a quien esté intentando seguirlo según lo subo (aunque casi sería mejor esperar un par de meses antes de verlo del tirón…)

Uno de los vídeos que subí ya habla sobre los átomos. Es un tipo de datos interesante para representar valores constantes que equivalen a su propio nombre. Al principio puede sonar raro. Al menos a mí me lo sonaba cuando vi por primera vez el concepto en Racket durante la universidad. En Racket, se les llama quotes, y se utiliza la tilde en vez de los dos puntos. Por ejemplo, 'banana, pero el principio es el mismo.

Una cosa que para no hacer un vídeo de nivel introductorio tan complejo no cuento, es que en la máquina virtual de Erlang, cada vez que se declara un átomo, se registra en una tabla de átomos (o Atom Table), que se comporta como un diccionario de átomos conocidos por la máquina virtual.

Si las operaciones que trabajan comparando átomos son rápidas (por ejemplo, x == :ok), lo es porque una vez que todos los átomos están indizados, a nivel interno la máquina virtual de Erlang no trata a un átomo como su valor, sino como su posición en la tabla, así que al final los átomos se gestionan también como números que representan posiciones, y sólo en el momento de comunicar un átomo al exterior es que vemos su representación alfanumérica.

Hablo siempre de alfanumérico porque un átomo contiene letras y caracteres del alfabeto, pero es importante distinguir que los identificadores en Elixir entienden de Unicode, y que por lo tanto, otros alfabetos diferentes también pueden ser codificados en átomos (:Βόρειος, mismamente).

Otra particularidad interesante es que el recolector de basura de Erlang nunca va a recolectar átomos que hayan caído en desuso. De modo que con el tiempo, la máquina virtual de Erlang va a tender a absorber todos aquellos átomos que hayan sido empleados. Dado que en Erlang ciertas construcciones como los propios nombres de los módulos o las listas de argumentos también se codifican con átomos, estas construcciones también van a tomar espacio.

Además, la tabla no es infinita. Los límites declarados por la máquina de Erlang avisan que, salvo que se modifique como parámetro al iniciar la máquina, como mucho se podrán declarar 1.048.576 átomos en la tabla. ¿Qué pasará cuando se alcance ese límite? Que la máquina fallará, como podemos probar rápidamente con este pequeño script:

for x <- 1..1048577, do: x |> Integer.to_string |> String.to_atom

Es una forma un poco fea y barata de generar 1.048.577 átomos a partir de cadenas de caracteres que generamos a su vez a partir de los números de un rango. Cuando ejecuto esto en mi máquina, la máquina de Erlang falla:

$ elixir foo.exs 
no more index entries in atom_tab (max=1048576)
Crash dump is being written to: erl_crash.dump…done