Aquí hay una buena manera de pensar sobre la diferencia entre los tipos de valor, el paso por valor, los tipos de referencia y el paso por referencia:
Una variable es un contenedor.
Una variable de tipo de valor contiene una instancia. Una variable de tipo de referencia contiene un puntero a una instancia almacenada en otro lugar.
La modificación de una variable de tipo de valor muta la instancia que contiene. La modificación de una variable de tipo de referencia muta la instancia a la que apunta.
Las variables de tipo de referencia separadas pueden apuntar a la misma instancia. Por lo tanto, la misma instancia puede ser mutada a través de cualquier variable que la señale.
Un argumento pasado por valor es un nuevo contenedor con una nueva copia del contenido. Un argumento pasado por referencia es el contenedor original con su contenido original.
Cuando un argumento de tipo valor se pasa por valor: la reasignación del contenido del argumento no tiene ningún efecto fuera del alcance, porque el contenedor es único. Modificar el argumento no tiene ningún efecto fuera del alcance, porque la instancia es una copia independiente.
Cuando un argumento de tipo de referencia se pasa por valor: la reasignación del contenido del argumento no tiene ningún efecto fuera del alcance, porque el contenedor es único. La modificación del contenido del argumento afecta el alcance externo, porque el puntero copiado apunta a una instancia compartida.
Cuando se pasa un argumento por referencia: la reasignación del contenido del argumento afecta el alcance externo, porque el contenedor se comparte. La modificación del contenido del argumento afecta el alcance externo, porque el contenido se comparte.
En conclusión:
Una variable de cadena es una variable de tipo de referencia. Por lo tanto, contiene un puntero a una instancia almacenada en otro lugar. Cuando se pasa por valor, su puntero se copia, por lo que modificar un argumento de cadena debería afectar la instancia compartida. Sin embargo, una instancia de cadena no tiene propiedades mutables, por lo que un argumento de cadena no se puede modificar de todos modos. Cuando se pasa por referencia, el contenedor del puntero se comparte, por lo que la reasignación seguirá afectando el alcance externo.