Pascal joue Go. Implémentation de méthodes et interfaces dans un compilateur amateur

Si je pouvais exporter une fonctionnalité de Go dans d'autres langues, ce serait des interfaces. - Russ Cox



Mon très simple compilateur Pascal est déjà devenu l'objet de deux publications sur Habré. Depuis leur écriture, le langage a acquis tous les outils manquants requis par le Pascal standard, et bon nombre des goodies que Borland a ajoutés à Pascal à son âge d'or. Le compilateur a également appris certaines des optimisations locales les plus simples, suffisantes ne serait-ce que pour empêcher vos yeux de saigner lorsque vous regardez la liste des désassembleurs.

Néanmoins, la jungle de la programmation orientée objet est restée complètement intacte. Alors pourquoi ne pas servir de terrain d'essai au compilateur pour expérimenter dans ce domaine? Et pourquoi ne nous inspirons-nous pas des paroles de Russ Cox, faites dans l'épigraphe? Essayons d'implémenter des méthodes et des interfaces de style Go en Pascal. L'idée est intéressante ne serait-ce que parce que tous les compilateurs Pascal populaires dans le passé (Delphi, Free Pascal) ont essentiellement emprunté le modèle objet à C ++. Il est intéressant de voir comment une approche complètement différente, empruntée à Go, prend racine sur le même terrain. Si vous êtes prêt à me suivre avec une bonne dose d'ironie, à laisser tomber la question «Pourquoi?» Et à prendre ce qui se passe comme un jeu, bienvenue au chat.

Principes


Par «Go style», nous comprendrons plusieurs principes sur la base desquels nous implémenterons des méthodes et des interfaces en Pascal:

  • Il n'y a pas de concepts indépendants de classe, d'objet, d'héritage.
  • La méthode peut être implémentée pour tout type de données particulier. Vous n'avez pas besoin de modifier la déclaration de type elle-même.
  • Une interface est compatible avec tout type de données particulier pour lequel toutes les méthodes répertoriées dans la déclaration d'interface sont implémentées. Une déclaration d'un type de données particulier ne nécessite pas qu'elle implémente une interface.

Implémentation


Pour déclarer des méthodes et des interfaces, les mots clés Pascal standard et l'interface sont utilisés dans le nouveau rôle. Aucun nouveau mot clé n'est entré. Le mot for est utilisé pour indiquer le nom et le type du destinataire de la méthode (dans la terminologie Go). Voici un exemple de description de méthode pour un type TCat précédemment déclaré avec un champ Name :

 procedure Greet for c: TCat (const HumanName: string); begin WriteLn('Meow, ' + HumanName + '! I am ' + c.Name); end; 

Le récepteur est en fait le premier argument de la méthode.

Une interface est une entrée Pascal normale, dans la déclaration dont le mot record est remplacé par le mot interface . Dans cet enregistrement, il n'est pas autorisé de déclarer des champs à l'exception des champs de type procédural. De plus, un champ Self masqué est ajouté au début de l'enregistrement. Il stocke un pointeur sur les données de ce type particulier, qui sont converties en un type d'interface. Voici un exemple de déclaration d'interface:

 type IPet = interface Greet: procedure (const HumanName: string); end; 

Lors de la conversion d'un type spécifique en interface, le compilateur vérifie la présence de toutes les méthodes requises par l'interface et la correspondance de leurs signatures. Ensuite, il définit le pointeur Self , remplit tous les champs procéduraux de l'interface avec des pointeurs vers des méthodes d'un type particulier.

Par rapport à Go, l'implémentation actuelle des interfaces en Pascal a des limites: il n'est pas possible d'interroger dynamiquement un type de données spécifique qui a été converti en un type d'interface. Par conséquent, les interfaces vides n'ont aucun sens. La prochaine étape de développement sera peut-être de combler cette lacune. Cependant, même dans leur forme actuelle, les interfaces fournissent un polymorphisme, utile dans de nombreuses tâches pas si banales. Nous examinerons un de ces problèmes.

Exemple


Un bon exemple d'utilisation d'interfaces est un programme de rendu de scènes tridimensionnelles utilisant la méthode de lancer de rayons. La scène se compose de corps géométriques simples: parallélépipèdes, sphères, etc. Chaque rayon émis par l'œil de l'observateur doit être suivi (à travers toutes ses réflexions) jusqu'à ce qu'il atteigne la source de lumière ou atteigne l'infini. Pour ce faire, une méthode d' Intersect est affectée à chaque type de corps, qui calcule les coordonnées du point où le rayon frappe la surface du corps et les composants normaux à ce point. La mise en œuvre de cette méthode pour différents types d'organes est différente. Par conséquent, les informations sur les corps sont commodément stockées dans un tableau d'entrées d'interface Body , et pour tous les éléments du tableau, la méthode Intersect est appelée tour à tour. L'interface redirige cet appel vers une méthode spécifique en fonction du type de corps.

Cela peut ressembler à une scène construite de la manière décrite:



Le code source complet du programme, y compris la description de la scène, prend 367 lignes.

Résumé


La mise en œuvre la plus simple du polymorphisme dans le propre compilateur de Pascal s'est avérée facile, portant rapidement les premiers fruits. On peut s'attendre à certaines complications dans la tâche de définition dynamique d'un type de données spécifique, qui a été converti en type d'interface. Les efforts nécessiteront également l'élimination des conflits non évidents avec les mécanismes de vérification de type standard de Pascal standard. Enfin, outre tous les soucis concernant les interfaces, une lutte inégale se poursuit avec Microsoft pour les fausses alarmes de leur Windows Defender lors du lancement de quelques exemples compilés.

Source: https://habr.com/ru/post/fr478630/


All Articles