Bitstrings

El último tipo de datos que vamos a ver es bitstring, y es literalmente eso: una cadena de bits. De este modo podemos guardar números con una longitud predefinida, como en los lenguajes de programación tradicionales. Además, binarios y su relación con las cadenas de caracteres. 00:00 Introducción a las bitstrings 04:32 Bitstrings con múltiples valores 05:18 Comparación de bitstrings 06:12 Binaries y su relación con los strings

El tipo bitstring en Elixir es una herramienta fascinante que nos permite representar números con una longitud específica en bits, algo que no es común en muchos lenguajes modernos. A diferencia de lenguajes como C o Java, donde los números tienen un tamaño fijo —por ejemplo, 2, 4 u 8 bytes— y pueden desbordarse si intentamos almacenar un valor demasiado grande, en Elixir los números pueden ser tan largos como queramos. Sin embargo, con bitstrings podemos imponer una longitud concreta en bits para representar un número, lo que abre posibilidades interesantes, especialmente para quienes trabajan con manipulación a nivel binario o aritmética modular.

Para crear un bitstring, utilizamos una sintaxis particular: dos signos menor que << seguidos de dos signos mayor que >>. Entre estos símbolos colocamos el número que queremos representar, seguido de dos puntos dobles :: y el número de bits que deseamos usar. Por ejemplo, para representar el número 14 con 4 bits escribiríamos:

<<14::4>>

Esto significa que estamos usando 4 bits para almacenar el número 14, lo cual es posible porque 4 bits pueden representar hasta 16 valores diferentes (de 0 a 15). Si intentamos representar un número que exceda la capacidad de bits asignada, como el 16 con 4 bits, el valor se desbordará y solo se conservarán los bits menos significativos, resultando en un valor incorrecto para nuestra intención original. Este comportamiento puede ser útil para ciertos cálculos, como la aritmética modular, donde los valores vuelven a empezar después de un límite.

Además, podemos concatenar varios valores dentro de un bitstring, separándolos por comas. Por ejemplo:

<<17::4, 10::4, 8::4>>

Esto crea un bitstring de 12 bits que contiene tres números representados con 4 bits cada uno. Un detalle curioso es que bitstrings con diferentes divisiones de bits pueden representar el mismo conjunto de bits. Por ejemplo, <<1::2, 3::2>> equivale a <<7::4>> porque ambos representan la secuencia binaria 0111. Esto nos permite comparar bitstrings basándonos en su contenido binario, sin importar cómo estén segmentados.

Un aspecto importante es que Elixir prefiere que los bitstrings tengan un tamaño múltiplo de 8 bits, es decir, un número entero de bytes. Cuando esto ocurre, el bitstring recibe un nombre especial: binary. Por ejemplo, <<25::8>> es un binary, y también <<25::16>> porque 16 es múltiplo de 8. Si el tamaño no es múltiplo de 8, entonces es simplemente un bitstring, pero no un binary. Podemos comprobar esto con las funciones is_bitstring/1 e is_binary/1:

is_bitstring(5)       # false, porque 5 es un número, no un bitstring
is_bitstring("5")     # true, porque las cadenas son bitstrings
is_binary("hola")     # true, porque las cadenas son binaries (bitstrings con tamaño múltiplo de 8)
is_binary(<<5::7>>)   # false, porque 7 no es múltiplo de 8

Aquí llegamos a un punto fundamental: las cadenas de texto en Elixir son en realidad bitstrings que cumplen la condición de ser binaries. Esto se debe a que cada carácter en una cadena está representado por un código Unicode, que puede ocupar varios bytes. Por eso, cuando hacemos is_bitstring("hola") o is_binary("hola"), ambas funciones devuelven true.

El hecho de que las cadenas sean bitstrings Unicode tiene implicaciones importantes. A diferencia de lenguajes como C, donde un carácter suele ocupar un byte, en Elixir cada carácter puede ocupar varios bytes para representar cualquier símbolo del vasto conjunto de caracteres Unicode. Esto permite manejar alfabetos muy diversos, desde el ruso o japonés hasta alfabetos menos comunes como el cuneiforme. Por lo tanto, el número de bytes en una cadena no tiene por qué coincidir con el número de caracteres visibles, algo que debemos tener en cuenta si venimos de otros lenguajes.

Podemos inspeccionar la representación interna de una cadena para ver cómo se codifican sus caracteres en números Unicode dentro de un bitstring:

IO.inspect("hola")
# Output: "hola"
IO.inspect(:erlang.bit_size("hola"))
# Output: 32 (4 caracteres * 8 bits)

Esto nos muestra que la cadena hola está compuesta por 4 caracteres, cada uno representado con 8 bits, sumando un total de 32 bits.

En resumen, el tipo bitstring nos ofrece un control muy fino sobre la representación binaria de datos en Elixir, y entenderlo nos ayuda a comprender mejor cómo funcionan internamente las cadenas de texto y otros tipos de datos en este lenguaje. Además, nos abre la puerta a manipulaciones a nivel de bits que pueden ser útiles en contextos específicos, como la aritmética modular o el procesamiento de datos binarios.

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