À quoi sert le «devenir» de Smalltalk?


12

Le become:message dans Smalltalk fait changer un objet en un autre, affectant toutes les références à lui.

Quelles sont les utilisations de cette fonctionnalité linguistique? Est-il utilisé dans du vrai code? Est-ce juste une curiosité? Est-il considéré comme une bonne / mauvaise pratique de l'utiliser?

Réponses:


11

Gilad Bracha parle become:longuement:

L'une des fonctionnalités les plus uniques et puissantes de Smalltalk est également l'une des moins connues en dehors de la communauté Smalltalk. C'est une petite méthode appelée devenir:.

Ce qui devient: ne fait qu'échanger les identités de son récepteur et de son argument. Autrement dit, après

a devenir: b

toutes les références à l'objet désigné par a avant le point d'appel se réfèrent à l'objet qui a été noté par b, et vice versa.

Prenez une minute pour intérioriser cela; vous pourriez le comprendre comme quelque chose de trivial. Il ne s'agit pas d'échanger deux variables - il s'agit littéralement d'un objet qui en devient un autre. Je ne connais aucune autre langue ayant cette fonctionnalité. C'est une caractéristique d'un pouvoir et d'un danger énormes.

Considérez la tâche d'étendre votre langage pour prendre en charge les objets persistants. Supposons que vous souhaitiez charger un objet à partir du disque, mais que vous ne souhaitiez pas charger tous les objets auxquels il se réfère de manière transitoire (sinon, il s'agit simplement d'une désérialisation d'objet simple). Donc, vous chargez l'objet lui-même, mais au lieu de charger ses références directes, vous les remplacez par des objets husk.

Les enveloppes représentent les vraies données sur le stockage secondaire. Ces données sont chargées paresseusement. Lorsque vous devez réellement invoquer une méthode sur une enveloppe, sa méthode doesNotUnderstand: charge l'objet de données correspondant à partir du disque (mais encore une fois, pas de manière transitoire).

Ensuite, il devient:, en remplaçant toutes les références à l'enveloppe par des références à l'objet nouvellement chargé, et relance l'appel.

Certains moteurs de persistance ont fait ce genre de choses pendant des décennies - mais ils s'appuyaient généralement sur un accès de bas niveau à la représentation. Devenir: vous permet de le faire au niveau du code source.

Maintenant, faites-le en Java. Ou même dans une autre langue dynamique. Vous reconnaîtrez que vous pouvez faire une forme générale d'avenir de cette façon, et donc la paresse. Le tout sans accès privilégié aux rouages ​​de l'implémentation. Il est également utile pour l'évolution du schéma - lorsque vous ajoutez une variable d'instance à une classe, par exemple. Vous pouvez «remodeler» toutes les instances selon vos besoins.

Bien sûr, vous ne devriez pas utiliser devenir: nonchalamment. Cela a un coût, qui peut être prohibitif dans de nombreuses implémentations. Au début de Smalltalks, devenir: était bon marché, car tous les objets étaient référencés indirectement au moyen d'une table d'objets. En l'absence d'une table d'objets, devient: parcourt le tas d'une manière similaire à un garbage collector. Plus vous avez de mémoire, plus cela devient cher: devient.

Le fait d'avoir une table d'objets prend du stockage et ralentit l'accès; mais cela vous offre une grande flexibilité. Le support matériel pourrait alléger la pénalité de performance. L'avantage est que de nombreux problèmes difficiles deviennent assez faciles à résoudre si vous êtes prêt à payer le coût de l'indirection via une table d'objets à l'avance. N'oubliez pas: chaque problème en informatique peut être résolu avec des niveaux supplémentaires d'indirection. Alex Warth a par exemple des travaux très intéressants qui entrent dans cette catégorie.

Devenir: a plusieurs variantes - une façon de devenir: change l'identité d'un objet A en celle d'un autre objet B, de sorte que les références à A pointent maintenant sur B; les références à B restent inchangées. Il est souvent utile de devenir: en vrac - la transmutation des identités de tous les objets d'un tableau (unidirectionnellement ou bidirectionnellement). Un groupe devenu: qui le fait par magie est idéal pour implémenter des mises à jour réfléchissantes d'un système, par exemple. Vous pouvez modifier tout un ensemble de classes et leurs instances en une seule fois.

Vous pouvez même concevoir un type sûr devenu:. Le bidirectionnel devient: le type n'est sûr que si le type de A est identique à celui de B, mais le bidirectionnel devient: nécessite uniquement que le nouvel objet soit un sous-type de l'ancien.

Il est peut-être temps de reconsidérer si le fait d'avoir une table d'objets est réellement une bonne chose.

En fait, ce que vous obtenez est une forme de chargement paresseux via ce qui équivaut à une métaprogrammation. Comme le souligne Bracha, cela peut être très utile mais c'est aussi dangereux car cela peut avoir un impact sérieux sur les performances.


Je serais plus inquiet de becomel'impact de ma santé mentale que de la performance de mon programme ...
Benjamin Hodgson

Hardware support could ease the performance penalty.De tous les endroits où j'ai entendu cela, la communauté Smalltalk a été la plus importante. Pourquoi devrions-nous «dépenser» des améliorations matérielles pour activer des paradigmes de programmation idéalistes alors que cela pourrait conduire à une augmentation des performances, une diminution de la consommation d'énergie ou une capacité accrue.
Alexander - Reinstate Monica

2

Il n'est pas beaucoup utilisé. Dans l'image Pharo 5 que j'ai ouverte, il y a 9 expéditeurs de #become :, 7 d'entre eux sont en tests unitaires. Il est utilisé dans le compilateur dans la génération de code et dans la bibliothèque de sérialisation Fuel pour remplacer les proxys par leur contenu.


Intéressant. À quoi servent les tests unitaires?
dpk

pour voir si ça marche ...
Stephan Eggermont
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.