En el nivel abstracto, puede incluir lo que quiera en un idioma que esté diseñando.
En el nivel de implementación, es inevitable que algunas de esas cosas sean más simples de implementar, algunas serán complicadas, algunas se pueden hacer rápido, algunas serán más lentas, etc. Para dar cuenta de esto, los diseñadores a menudo tienen que tomar decisiones difíciles y compromisos.
A nivel de implementación, una de las formas más rápidas que hemos encontrado para acceder a una variable es encontrar 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 conocer el tamaño de una variable, el compilador necesitaría 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 base.
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 acceda de una manera que normalmente llamaría eficiente. Pero hay una manera de mover un poco las cosas y usar una variable no para almacenar el objeto, sino para identificar el objeto y dejar que ese objeto se almacene en otro lugar. Esa es una referencia (por ejemplo, una dirección de memoria): un nivel adicional de indirección que asegura que una variable solo necesita contener algún tipo de información de tamaño fijo, siempre que podamos encontrar el objeto a través de esa información. Para lograr eso, solo tenemos que cargar la dirección (tamaño fijo) y luego podemos trabajar como de costumbre usando los desplazamientos del objeto que sabemos que son válidos, incluso si ese objeto tiene más datos en los desplazamientos que no conocemos. Podemos hacer eso porque no lo hacemos
En el nivel abstracto, este método le permite almacenar una (referencia a) string
en una object
variable sin perder la información que la convierte en a string
. Está bien que todos los tipos trabajen así y también se 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 algo más lento. Puede permitir que el compilador exprima más rendimiento de un programa si incluye en su idioma algunos tipos comúnmente utilizados que no tienen ese nivel adicional de indirección (la referencia). Pero al eliminar ese nivel de indirección, el compilador ya no puede permitirle subtipear de forma segura en la memoria. Esto se debe a que si agrega más miembros de datos a su tipo y lo asigna a un tipo más general, todos los miembros de datos adicionales que no quepan en el espacio asignado para la variable de destino se cortarán.