En Scala, todo es un objeto, y esto incluye incluso los números y tipos que en otros lenguajes suelen ser primitivos. A diferencia de Java, donde un int es un tipo primitivo y solo puede ser envuelto en clases como Integer, en Scala los valores como 5 son objetos por sí mismos. Esto significa que no necesitamos tipos envolventes para trabajar con ellos, ya que todos los valores, desde enteros hasta booleanos, son instancias de clases.
Dentro de Scala, los tipos básicos que representan valores se agrupan bajo el tipo AnyVal. Este incluye tipos como Int, Long, Double, Float, Byte, Short, Char, Boolean y también Unit, que es el tipo que usan las funciones que no devuelven nada. Todos estos son objetos que representan valores y forman parte de esta categoría especial.
Por otro lado, tenemos los tipos AnyRef, que representan referencias a objetos. Si venimos de Java, podemos pensar en ellos como equivalentes a las instancias de clases que manejamos habitualmente. Por ejemplo, cuando creamos una lista o un array en Scala, estamos trabajando con objetos de tipo AnyRef. También, si usamos clases de Java dentro de Scala, como java.util.ArrayList, estas se tratan como AnyRef. Lo mismo ocurre con las cadenas de texto (String) y nuestras propias clases definidas en Scala.
Ambos, AnyVal y AnyRef, derivan de un tipo común llamado Any, que es la raíz de todo el sistema de tipos en Scala. Esto significa que cualquier valor o referencia que manejemos en Scala es, en última instancia, un Any.
Además de estos, Scala tiene tipos especiales que juegan un papel importante en la organización del sistema de tipos. Uno de ellos es Null, que representa la ausencia de valor para cualquier tipo de referencia (AnyRef). Por ejemplo, una cadena o un objeto pueden tener el valor null. Aunque podemos usar null en funciones, no es lo más recomendable. Scala ofrece una alternativa más segura llamada Option, que permite manejar valores que pueden o no estar presentes sin recurrir a null.
Otro tipo especial es Nothing, que es un concepto un poco más abstracto. Nothing es un subtipo de todos los tipos, lo que significa que es compatible con cualquier tipo en Scala. Sin embargo, no se puede instanciar, es decir, no podemos crear objetos de tipo Nothing. Su uso principal es en funciones que nunca retornan un valor, como aquellas que contienen bucles infinitos o que lanzan excepciones. En estos casos, Nothing indica que la función no tiene un valor de retorno normal. Además, desde el punto de vista de la máquina virtual, usar Nothing puede ser más eficiente que usar Unit en estas situaciones, ya que Unit sí tiene una instancia, aunque no contenga información útil.
Para ilustrar cómo podemos asignar valores en Scala, simplemente declaramos variables o constantes sin necesidad de punto y coma, por ejemplo:
val cinco = 5
var j = 10
Aquí, cinco es un valor de tipo Int (que es un AnyVal), y j es una variable mutable también de tipo Int.
En resumen, el sistema de tipos de Scala está organizado de manera que todo es un objeto, con Any como la raíz. Desde ahí, se bifurca en AnyVal para valores y AnyRef para referencias, y cuenta con tipos especiales como Null y Nothing para manejar casos particulares de ausencia de valor o funciones que no retornan. Esta estructura nos permite trabajar con un sistema de tipos muy coherente y potente, que facilita la programación funcional y orientada a objetos en Scala.