En el nivel abstracto, puedes incluir lo que quieras en un idioma que estés diseñando.
A nivel de implementación, es inevitable que algunas de esas cosas sean más fáciles de implementar, algunas sean complicadas, algunas se puedan acelerar, otras deban ser más lentas, y así sucesivamente. Para dar cuenta de esto, los diseñadores a menudo tienen que tomar decisiones difíciles y compromisos.
En el nivel de implementación, una de las maneras más rápidas para acceder a una variable es averiguar su dirección y cargar el contenido de esa dirección. Hay instrucciones específicas en la mayoría de las CPU para cargar datos desde direcciones y esas instrucciones generalmente necesitan saber cuántos bytes necesitan cargar (uno, dos, cuatro, ocho, etc.) y dónde colocar los datos que cargan (registro único, registro par, registro extendido, otra memoria, etc). Al conocer el tamaño de una variable, el compilador puede saber exactamente qué instrucción emitir para los usos de esa variable. Al no saber el tamaño de una variable, el compilador tendría que recurrir a algo más complicado y probablemente más lento.
En el nivel abstracto, el punto de subtipo es poder usar instancias de un tipo donde se espera un tipo igual o más general. En otras palabras, se puede escribir un código que espere un objeto de un tipo particular o algo más derivado, sin saber de antemano qué sería exactamente esto. Y claramente, como más tipos derivados pueden agregar más miembros de datos, un tipo derivado no necesariamente tiene los mismos requisitos de memoria que sus tipos básicos.
En el nivel de implementación, no hay una manera simple para que una variable de un tamaño predeterminado contenga una instancia de tamaño desconocido y se pueda acceder a ella de una manera que normalmente llamaría eficiente. Pero hay una manera de mover las cosas un poco y usar una variable no para almacenar el objeto, sino para identificar el objeto y dejar que ese objeto se almacene en otro lugar. De esa manera es una referencia (por ejemplo, una dirección de memoria), un nivel adicional de direccionamiento indirecto que garantiza que una variable solo necesita mantener algún tipo de información de tamaño fijo, siempre que podamos encontrar el objeto a través de esa información. Para lograrlo, solo tenemos que cargar la dirección (tamaño fijo) y luego podemos trabajar como de costumbre con las compensaciones del objeto que sabemos que son válidas, incluso si ese objeto tiene más datos en las compensaciones que no sabemos. Podemos hacerlo porque ya no nos preocupamos por sus requisitos de almacenamiento cuando accedemos a él.
En el nivel abstracto, este método le permite almacenar una (referencia a a) string
en una variable object
sin perder la información que hace que sea un string
. Está bien que todos los tipos funcionen de esta manera y también podría decir que es elegante en muchos aspectos.
Aún así, en el nivel de implementación, el nivel adicional de indirección implica más instrucciones y en la mayoría de las arquitecturas hace que cada acceso al objeto sea un poco más lento. Puede permitir que el compilador exprima más rendimiento de un programa si incluye en su idioma algunos tipos de uso común que no tienen ese nivel adicional de indirección (la referencia). Pero al eliminar ese nivel de direccionamiento indirecto, el compilador ya no puede permitirte subtitular de forma segura en memoria. Esto se debe a que si agrega más miembros de datos a su tipo y los asigna a un tipo más general, todos los miembros de datos adicionales que no encajen en el espacio asignado para la variable de destino se eliminarán.