No nível abstrato, você pode incluir o que quiser em um idioma que estiver criando.
No nível da implementação, é inevitável que algumas dessas coisas sejam mais simples de implementar, algumas serão complicadas, outras podem ser feitas rapidamente, outras são mais lentas e assim por diante. Para explicar isso, os designers geralmente precisam tomar decisões e compromissos difíceis.
No nível da implementação, uma das maneiras mais rápidas de acessar uma variável é descobrir o endereço e carregar o conteúdo desse endereço. Existem instruções específicas na maioria das CPUs para carregar dados de endereços e essas instruções geralmente precisam saber quantos bytes eles precisam carregar (um, dois, quatro, oito, etc.) e onde colocar os dados que eles carregam (registro único, registro par, registro estendido, outra memória etc.). Ao saber o tamanho de uma variável, o compilador pode saber exatamente qual instrução emitir para o uso dessa variável. Por não saber o tamanho de uma variável, o compilador precisaria recorrer a algo mais complicado e provavelmente mais lento.
No nível abstrato, o ponto de subtipagem é poder usar instâncias de um tipo em que é esperado um tipo igual ou mais geral. Em outras palavras, pode ser escrito código que espera um objeto de um tipo específico ou algo mais derivado, sem saber antecipadamente o que exatamente seria isso. E claramente, como mais tipos derivados podem adicionar mais membros de dados, um tipo derivado não necessariamente tem os mesmos requisitos de memória que seus tipos básicos.
No nível da implementação, não há uma maneira simples de uma variável de tamanho predeterminado manter uma instância de tamanho desconhecido e ser acessada da maneira que você normalmente chamaria de eficiente. Mas há uma maneira de mudar um pouco as coisas e usar uma variável não para armazenar o objeto, mas para identificá-lo e permitir que ele seja armazenado em outro lugar. Dessa maneira, é uma referência (por exemplo, um endereço de memória) - um nível extra de indireção que garante que uma variável precise armazenar apenas algum tipo de informação de tamanho fixo, desde que possamos encontrar o objeto através dessa informação. Para conseguir isso, precisamos carregar o endereço (tamanho fixo) e, em seguida, trabalhar como de costume, usando as compensações do objeto que sabemos que são válidas, mesmo que esse objeto tenha mais dados em compensações que não conhecemos. Podemos fazer isso porque não '
No nível abstrato, esse método permite armazenar a (referência a) string
em uma object
variável sem perder as informações que a tornam uma string
. É bom que todos os tipos funcionem assim e você também pode dizer que é elegante em muitos aspectos.
Ainda, no nível de implementação, o nível extra de indireção envolve mais instruções e, na maioria das arquiteturas, torna cada acesso ao objeto um pouco mais lento. Você pode permitir que o compilador reduza mais o desempenho de um programa se incluir no seu idioma alguns tipos comumente usados que não possuem esse nível extra de indireção (a referência). Mas, ao remover esse nível de indireção, o compilador não pode mais permitir que você subtipo de forma segura a memória. Isso ocorre porque, se você adicionar mais membros de dados ao seu tipo e atribuir a um tipo mais geral, quaisquer membros de dados extras que não couberem no espaço alocado para a variável de destino serão cortados.