C'est un point crucial, mais à mon humble avis, cela vaut la peine d'être compris.
Toutes les langues OO font toujours des copies de références, et ne copient jamais un objet «de manière invisible». Il serait beaucoup plus difficile d'écrire des programmes si les langues OO fonctionnaient d'une autre manière. Par exemple, les fonctions et les méthodes n'ont jamais pu mettre à jour un objet. Java et la plupart des langages OO seraient presque impossibles à utiliser sans une complexité supplémentaire importante.
Un objet dans un programme est censé avoir une signification. Par exemple, il représente quelque chose de spécifique dans le monde physique réel. Il est généralement logique d'avoir de nombreuses références à la même chose. Par exemple, mon adresse personnelle peut être communiquée à de nombreuses personnes et organisations, et cette adresse fait toujours référence au même emplacement physique. Donc, le premier point est que les objets représentent souvent quelque chose de spécifique, réel ou concret; et donc être capable d'avoir de nombreuses références à la même chose est extrêmement utile. Sinon, il serait plus difficile d'écrire des programmes.
Chaque fois que tu passes a
comme argument / paramètre à une autre fonction, par exemple en appelant
foo(Dog aDoggy);
ou en appliquant une méthode à a
, le code de programme sous-jacent fait une copie de la référence, pour produire une deuxième référence au même objet.
De plus, si le code avec une référence copiée se trouve dans un thread différent, les deux peuvent être utilisés simultanément pour accéder au même objet.
Ainsi, dans la plupart des programmes utiles, il y aura plusieurs références au même objet, car c'est la sémantique de la plupart des langages de programmation OO.
Maintenant, si nous y réfléchissons, car le passage par référence est le seul mécanisme disponible dans de nombreux langages OO (C ++ prend en charge les deux), nous pourrions nous attendre à ce qu'il soit le `` bon '' comportement par défaut .
À mon humble avis, l'utilisation de références est la bonne valeur par défaut , pour deux raisons:
- Il garantit que la valeur d'un objet utilisé à deux endroits différents est la même. Imaginez mettre un objet dans deux structures de données différentes (tableaux, listes, etc.) et effectuer certaines opérations sur un objet qui le modifie. Cela pourrait être un cauchemar à déboguer. Plus important encore, il est le même objet dans les deux structures de données, ou le programme a un bug.
- Vous pouvez joyeusement refactoriser le code en plusieurs fonctions, ou fusionner le code de plusieurs fonctions en une seule, et la sémantique ne change pas. Si le langage ne fournissait pas de sémantique de référence, il serait encore plus complexe de modifier le code.
Il y a aussi un argument d'efficacité; la copie d'objets entiers est moins efficace que la copie d'une référence. Cependant, je pense que cela manque le point. Les références multiples au même objet ont plus de sens et sont plus faciles à utiliser, car elles correspondent à la sémantique du monde physique réel.
Donc, à mon humble avis, il est généralement logique d'avoir plusieurs références au même objet. Dans les cas inhabituels où cela n'a pas de sens dans le contexte d'un algorithme, la plupart des langues offrent la possibilité de faire un «clone» ou une copie complète. Cependant, ce n'est pas la valeur par défaut.
Je pense que les gens qui soutiennent que cela ne devrait pas être la valeur par défaut utilisent un langage qui ne fournit pas de collecte automatique des ordures. Par exemple, le C ++ à l'ancienne. Le problème est qu'ils doivent trouver un moyen de collecter des objets «morts» et non de récupérer des objets qui pourraient encore être nécessaires; avoir plusieurs références au même objet rend cela difficile.
Je pense que si C ++ avait une collecte des ordures suffisamment peu coûteuse, de sorte que tous les objets référencés soient récupérés, alors une grande partie de l'objection disparaît. Il y aura toujours des cas où la sémantique de référence n'est pas ce qui est nécessaire. Cependant, d'après mon expérience, les personnes qui peuvent identifier ces situations sont également généralement capables de choisir la sémantique appropriée de toute façon.
Je crois qu'il existe des preuves qu'une grande quantité de code dans un programme C ++ est là pour gérer ou atténuer la collecte des ordures. Cependant, l'écriture et le maintien de ce type de code «infrastructurel» augmentent les coûts; il est là pour rendre le langage plus facile à utiliser ou plus robuste. Ainsi, par exemple, le langage Go est conçu en mettant l'accent sur la correction de certaines des faiblesses de C ++, et il n'a pas d'autre choix que la récupération de place.
Ceci n'est bien sûr pas pertinent dans le contexte de Java. Il a également été conçu pour être facile à utiliser, tout comme la collecte des ordures. Par conséquent, avoir plusieurs références est la sémantique par défaut et est relativement sûr dans le sens où les objets ne sont pas récupérés tant qu'il y a une référence à eux. Bien sûr, ils peuvent être conservés par une structure de données car le programme ne se range pas correctement lorsqu'il a vraiment fini avec un objet.
Donc, en revenant à votre question (avec un peu de généralisation), quand voudriez-vous plus d'une référence au même objet? À peu près dans toutes les situations auxquelles je peux penser. Ils sont la sémantique par défaut du mécanisme de passage de paramètres de la plupart des langues. Je suggère que c'est parce que la sémantique par défaut de la manipulation des objets qui existe dans le monde réel doit à peu près être par référence ('car les objets réels sont là-bas).
Toute autre sémantique serait plus difficile à gérer.
Dog a = new Dog("rover"); // initialise with name
DogList dl = new DogList()
dl.add(a)
...
a.setOwner("Mr Been")
Je suggère que le "rover" dans dl
soit celui effectué par setOwner
ou les programmes deviennent difficiles à écrire, à comprendre, à déboguer ou à modifier. Je pense que la plupart des programmeurs seraient perplexes ou consternés autrement.
plus tard, le chien est vendu:
soldDog = dl.lookupOwner("rover", "Mr Been")
soldDog.setOwner("Mr Mcgoo")
Ce type de traitement est courant et normal. La sémantique de référence est donc la valeur par défaut, car elle est généralement plus logique.
Résumé: Il est toujours judicieux d'avoir plusieurs références au même objet.