tipo-valor-y-referencia

Tipo valor y referencia

Ya hemos visto qué son las REFERENCIAS, elementos que contiene un vínculo a otro elemento. Si aún no lo habéis visto, conviene que le echéis un ojo a esto Qué es una referencia.

Ahora vamos ver que implicaciones tiene las referencias en el ámbito de la informática y de la programación (en particular, en la gestión de nuestras variables).

De hecho, la mayoría de lenguaje dividen sus variables en dos tipos:

  • Variables de tipo valor
  • Variables de tipo referencia

El concepto de REFERENCIA está muy “en el core” de tu ordenador. Forma un papel crucial en la gestión de memoria y el funcionamiento interno del mismo.

Estos dos tipos, valor y referencia, tienen comportamientos distintos dentro de un programa, que afectan a muchisimos aspectos (como velocidad, mutabilidad, memoria dinámica).

Así que es importante entenderlo para que no metas la pata (y por culturilla general, que tampoco está mal). Así que vamos al lio 👇.

Qué son los tipos de valor y los tipos de referencia

Las variables de tipo valor son aquellas en la que los los datos se almacenan directamente en la variable.

Es decir, tu variable tiene un “huequito” para meter su valor.

tipo-valor

En general, los tipo valor se limitan a los tipos más sencillos (primitivos) de cada lenguaje. En particular, normalmente son únicamente:

  • Números enteros, y de coma flotante
  • Caracteres (no strings)
  • Booleanos
  • Agrupaciones de variables sencillas

Esto significa que cuando asignamos una variable a otra, se realiza una copia independiente de los datos.

Las variables de tipo referencia son aquellos en los que las variables contienen referencias a los datos en lugar de los datos en sí mismos.

Es decir, tu variable contiene un enlace a unos datos, que están “en otro lado”.

En realidad la REFERENCIA sí tiene un valor. Lo que pasa es que el valor, es la forma de llegar a los datos (la dirección).

tipo-referencia

Los tipos de referencia incluyen:

  • Colecciones (arrays, listas, diccionarios…)
  • Objetos
  • Estructuras de datos complejas

Es decir, básicamente todo son REFERENCIAS. Excepto los números, los caracteres… y poquito más.

Diferencias entre tipos de valor y tipos de referencia

La principal diferencia entre un tipo valor y un tipo referencia es cómo se comportan cuando se copian.

Vamos a verlo haciendo un ejemplo. Hacemos el mismo experimento, con estos pasos:

  1. Creamos una variable A y le asignamos un valor
  2. Creamos otra variable B y la igualamos a A
  3. Modificamos B
  4. Vemos que le pasa ha pasado a A

En resumen, queremos saber si modificar B también modifica A.

Empecemos por un tipo valor. Por ejemplo, un número entero

int A = 10;  // creamos una variable A, y le ponemos valor 10
int B = A;   // creamos una variable B, y le ponemos valor A

int B = 20;  // cambiamos B. ¿Ha cambiado A?

¿Cuánto vale A al final del proceso? En este caso, A vale 10 y B vale 20.

Con tipo valor: Modificar B -> NO ❌ ha modificado a A

Esto es así por porque A y B son tipo valor, son independientes. Cada uno tiene su propio valor.

tipo-valor-ejemplo

Al copiar el valor de A en B, hemos copiado su valor, pero siguen siendo variables separadas. Cualquier cambio posterior no afecta a la otra, porque no hay un vínculo entre ellas.

Ahora vamos a hacer lo mismo con un tipo referencia. Por ejemplo, vamos a coger un array (solo vamos a trabajar con la posición 0 del array, suficiente para mostrar lo que queremos ver).

Así que hacemos el mismo experimento:

int[] A = {10, 0, 0};  // creamos una variable A
int[] B = A;           // creamos una variable B, y le ponemos valor A

B[0] = 20;             // cambiamos B. ¿Ha cambiado A?

¿Cuánto vale A[0]? En en este caso, A[0] vale 20.

Con tipo referencia: Modificar B -> SI ✔️ ha modificado a A

Esto ha pasado porque estamos trabajando con tipo referencia. Al crear la variable A, esta era una referencia a un array. Al crear la nueva variable B, hemos igualado a A. Por lo cuál, teníamos dos referencias, que apuntaban al mismo Array.

tipo-referencia-ejemplo

Por tanto, si modificamos cualquier cosa en B, estamos modificándola en A. Porque las dos variables apuntan a los mismos datos.

Si quisiéramos volver a hacerlas independientes, tendríamos que asignar a B un Array diferente.

int[] A = {10, 0, 0};   // creamos una variable A
int[] B = A;            // A y B apuntan a los mismos datos


int[] B = {10, 0, 0};   // ahora B apunta a otro Array
B[0] = 20;              // si cambiamos B, ya no afecta a A

tipo-referencia-ejemplo-2

Funcionamiento interno Avanzado

Lo primero que tenéis que saber es que la memoria se organiza en celdas. Cada una de estas celdas están identificadas con un número.

tipo-valor-referencia-interno-1

Cuando creamos una variable como A o B, el programa toma esto como alias para direcciones de memoria. Internamente el ordenador ni ve tus alias A ni B. El lo traduce a, por ejemplo, 0x17 y 0x21 (o los que le toquen). Y sólo trabaja con eso.

La trabajar con variables de tipo valor, en estas casillas de memoria va a meter el valor de tu variable. En nuestro ejemplo, 10. Pero son dos casillas independientes. Si en una pongo 20, la otra no se ve afectada.

tipo-valor-referencia-interno-2

Cuando tienes variables de tipo referencia, igualmente tienes dos casillas para tus variables. Pero, en vez de tener el valor, esta vez tienen la dirección de memoria donde están los datos “de verdad”.

En nuestro ejemplo, digamos que tenemos un ARRAY. El ordenador ha creado este array en la posición 0x30. Nuestras variables A y B, tienen esta posición como valor.

tipo-valor-referencia-interno-3

Así que, tanto A como B están modificando los mismos datos, que realmente están en la posición de memoria 0x30.

Por otro lado, tu lenguaje de programación sabe tratar ambos tipos. Cuando accede a:

  • tipo valor: Sabe que tiene el valor disponible en la dirección que sea
  • tipo referencia: Sabe que es una dirección de memoria, y que tiene que dar “un salto” a los datos

A esa operación de “salto” que tiene que hacer con los tipo referencia para llegar a los datos de verdad se le llama indirección.

En principio, es el motivo por el que acceder a una variable de tipo referencia sean un poquito más lentos que los tipos valor. Pero es tan habitual y está tan optimizada que la diferencia suele ser mínima o incluso nula. Pero ahí está.

Por el contrario, los tipo referencia son muchísimo más rápidos de copiar o mover. Esto es así porque realmente no copias los datos, únicamente copias la dirección de memoria. Que, en general, ocupa unos pocos bytes. Mientras los datos reales pueden ser… pues todo lo grande que te deje la memoria de tu ordenador.