Au niveau abstrait, vous pouvez inclure tout ce que vous voulez dans la langue que vous concevez.
Au niveau de la mise en œuvre, il est inévitable que certaines de ces choses soient plus simples à mettre en œuvre, que certaines soient compliquées, que certaines soient rapides, que certaines soient forcément plus lentes, etc. Pour en tenir compte, les concepteurs doivent souvent prendre des décisions difficiles et faire des compromis.
Au niveau de la mise en œuvre, l’un des moyens les plus rapides pour accéder à une variable est de trouver son adresse et de charger le contenu de cette adresse. Il existe des instructions spécifiques dans la plupart des CPU pour le chargement des données à partir d’adresses et ces instructions ont généralement besoin de savoir combien d’octets elles doivent charger (un, deux, quatre, huit, etc.) et où placer les données qu’elles chargent (registre unique, registre). paire, registre étendu, autre mémoire, etc.). En connaissant la taille d'une variable, le compilateur peut savoir exactement quelle instruction émettre pour les utilisations de cette variable. En ignorant la taille d'une variable, le compilateur devrait recourir à quelque chose de plus compliqué et probablement plus lent.
Au niveau abstrait, le point de sous-typage est de pouvoir utiliser des instances d'un type où un type égal ou plus général est attendu. En d'autres termes, il est possible d'écrire du code qui attend un objet d'un type particulier ou quoi que ce soit de plus dérivé, sans savoir à l'avance ce que ce serait exactement. Et, de toute évidence, étant donné que plus de types dérivés peuvent ajouter plus de membres de données, un type dérivé n’a pas nécessairement les mêmes besoins en mémoire que ses types de base.
Au niveau de la mise en œuvre, il n’existe aucun moyen simple pour une variable d’une taille prédéterminée de contenir une instance de taille inconnue et d’y accéder de la manière que vous appelleriez normalement efficace. Mais il existe un moyen de déplacer un peu les choses et d'utiliser une variable non pour stocker l'objet, mais pour identifier l'objet et laisser cet objet être stocké ailleurs. De cette façon, il s’agit d’une référence (par exemple une adresse de mémoire) - un niveau supplémentaire d’indirection qui garantit qu’une variable doit seulement contenir une sorte d’information de taille fixe, tant que nous pouvons trouver l’objet à travers cette information. Pour ce faire, il suffit de charger l’adresse (taille fixe), puis de travailler comme d’habitude en utilisant les décalages de l’objet que nous savons valables, même si cet objet a plus de données en décalage que nous ne connaissons pas. Nous pouvons le faire parce que nous ne
Au niveau abstrait, cette méthode vous permet de stocker une (référence à a) string
dans une object
variable sans perdre les informations qui la rendent a string
. Cela convient à tous les types de travailler comme ça et vous pourriez aussi dire que c'est élégant à bien des égards.
Néanmoins, au niveau de la mise en œuvre, le niveau supplémentaire d'indirection implique plus d'instructions et rend la plupart des architectures plus lentes chaque accès à l'objet. Vous pouvez autoriser le compilateur à augmenter les performances d'un programme si vous incluez dans votre langage certains types couramment utilisés qui ne possèdent pas ce niveau supplémentaire d'indirection (la référence). Mais en supprimant ce niveau d'indirection, le compilateur ne peut plus vous permettre de sous-taper de manière sécurisée pour la mémoire. En effet, si vous ajoutez plus de membres de données à votre type et que vous affectez un type plus général, tous les membres de données supplémentaires qui ne rentrent pas dans l'espace alloué à la variable cible seront découpés en tranches.