web-dev-qa-db-fra.com

Qu'est-ce qui rend la surcharge de l'opérateur de Scala «bonne», mais «mauvaise» pour C ++?

La surcharge des opérateurs en C++ est considérée par beaucoup comme une mauvaise chose (tm), et une erreur à ne pas répéter dans les nouveaux langages. Certes, c'était une fonctionnalité spécifiquement abandonnée lors de la conception de Java.

Maintenant que j'ai commencé à lire sur Scala, je trouve qu'il a ce qui ressemble beaucoup à une surcharge d'opérateur (bien que techniquement il n'y ait pas de surcharge d'opérateur parce qu'il n'a pas d'opérateurs, seulement des fonctions). Cependant, il ne semble pas être qualitativement différent de la surcharge d'opérateur en C++, où, si je me souviens bien, les opérateurs sont définis comme des fonctions spéciales.

Donc ma question est de savoir ce qui fait que l'idée de définir "+" en Scala une meilleure idée qu'en C++?

153
skaffman

C++ hérite des vrais opérateurs bleus de C. J'entends par là que le "+" dans 6 + 4 est très spécial. Vous ne pouvez pas, par exemple, obtenir un pointeur vers cette fonction +.

Scala, d'autre part, n'a pas d'opérateurs de cette façon. Il a juste une grande flexibilité dans la définition des noms de méthode et un peu de priorité intégrée pour les symboles non Word. Donc techniquement Scala n'a pas de surcharge d'opérateur.

Peu importe comment vous voulez l'appeler, la surcharge des opérateurs n'est pas intrinsèquement mauvaise, même en C++. Le problème est lorsque de mauvais programmeurs en abusent. Mais franchement, je suis d'avis que la suppression de la capacité des programmeurs à abuser de la surcharge des opérateurs ne met pas un frein à la réparation de tout ce que les programmeurs peuvent abuser. La vraie réponse est le mentorat. http://james-iry.blogspot.com/2009/03/operator-overloading-ad-absurdum.html

Néanmoins, il existe des différences entre la surcharge d'opérateur de C++ et la dénomination de méthode flexible de Scala qui, à mon humble avis, rendent Scala à la fois moins abusif et plus abusif.

En C++, la seule façon d'obtenir une notation in-fix est d'utiliser des opérateurs. Sinon, vous devez utiliser object.message (argument) ou pointer-> messsage (argument) ou function (argument1, argument2). Donc, si vous voulez un certain style DSLish à votre code, il y a une pression pour utiliser des opérateurs.

Dans Scala vous pouvez obtenir la notation infixe avec n'importe quel envoi de message. "Argument de message d'objet" est parfaitement correct, ce qui signifie que vous n'avez pas besoin d'utiliser des symboles non-Word juste pour obtenir la notation infixe.

La surcharge des opérateurs C++ se limite essentiellement aux opérateurs C. Combiné avec la limitation que seuls les opérateurs peuvent être utilisés infixe qui met la pression sur les gens pour essayer de mapper un large éventail de concepts non liés sur quelques symboles comme "+" et ">>"

Scala autorise une vaste gamme de symboles non Word valides comme noms de méthode. Par exemple, j'ai un DSL Prolog-ish intégré où vous pouvez écrire

female('jane)!         // jane is female
parent('jane,'john)!   // jane is john's parent
parent('jane, 'wendy)! // jane is wendy's parent

mother('Mother, 'Child) :- parent('Mother, 'Child) & female('Mother) //'// a mother of a child is the child's parent and is female

mother('X, 'john)?  // find john's mother
mother('jane, 'X)?  // find's all of jane's children

Les symboles: -,!,? Et & sont définis comme des méthodes ordinaires. En C++ uniquement & serait valide, donc une tentative de mapper ce DSL en C++ nécessiterait des symboles qui évoquent déjà des concepts très différents.

Bien sûr, cela ouvre également Scala à un autre type d'abus. Dans Scala vous pouvez nommer une méthode $! & ^% Si vous le souhaitez).

Pour d'autres langages qui, comme Scala, sont flexibles dans l'utilisation des noms de fonction et de méthode non Word, voir Smalltalk où, comme Scala, chaque "opérateur" n'est qu'une autre méthode et Haskell qui permet au programmeur de définir la priorité et la fixité des noms flexibles les fonctions.

238
James Iry

La surcharge des opérateurs en C++ est considérée par beaucoup comme une mauvaise chose (tm)

Seulement par les ignorants. Il est absolument nécessaire dans un langage comme C++, et il est à noter que d'autres langages qui ont commencé à adopter une vision "puriste" l'ont ajouté une fois que leurs concepteurs ont découvert à quel point il était nécessaire.

65
anon

La surcharge des opérateurs n'a jamais été universellement considérée comme une mauvaise idée en C++ - juste l'abus de la surcharge des opérateurs était considéré comme une mauvaise idée. On n'a pas vraiment besoin d'une surcharge d'opérateur dans un langage car ils peuvent de toute façon être simulés avec des appels de fonction plus verbeux. Éviter la surcharge des opérateurs dans Java a rendu l'implémentation et la spécification de Java un peu plus simple et obligé les programmeurs à ne pas abuser des opérateurs. Il y a eu un débat dans le = Java communauté sur l'introduction de la surcharge d'opérateur.

Les avantages et les inconvénients de la surcharge d'opérateur en Scala sont les mêmes qu'en C++ - vous pouvez écrire du code plus naturel si vous utilisez la surcharge d'opérateur de manière appropriée - et du code plus crypté et obscurci si vous ne le faites pas.

FYI: les opérateurs ne sont pas définis comme des fonctions spéciales en C++, ils se comportent comme n'importe quelle autre fonction - bien qu'il existe des différences dans la recherche de nom, si elles doivent être des fonctions membres et le fait qu'elles peuvent être appelées de deux manières: 1 ) syntaxe d'opérateur, et 2) syntaxe d'opérateur-fonction-id.

41
Faisal Vali

Cet article - " L'héritage positif de C++ et Java " - répond directement à votre question.

"C++ a à la fois une allocation de pile et une allocation de tas et vous devez surcharger vos opérateurs pour gérer toutes les situations et ne pas provoquer de fuites de mémoire. Difficile en effet. Java, cependant, a un mécanisme d'allocation de stockage unique et un garbage collector, ce qui rend la surcharge des opérateurs triviale". ..

Java a tort (selon l'auteur) omis la surcharge des opérateurs car c'était compliqué en C++, mais a oublié pourquoi (ou ne s'est pas rendu compte que cela ne s'appliquait pas à Java).

Heureusement, les langages de niveau supérieur comme Scala donnent aux développeurs des options, tout en fonctionnant sur la même JVM.

18
jmanning2k

Il n'y a rien de mal à la surcharge de l'opérateur. En fait, il y a quelque chose qui ne va pas avec pas ayant une surcharge d'opérateur pour les types numériques. (Jetez un œil à certains Java qui utilise BigInteger et BigDecimal.)

C++ a cependant l'habitude d'abuser de cette fonctionnalité. Un exemple souvent cité est que les opérateurs de décalage de bits sont surchargés pour effectuer des E/S.

9
dan04

En général, ce n'est pas une mauvaise chose.
Les nouveaux langages tels que C # ont également une surcharge d'opérateur.

C'est l'abus de surcharge de l'opérateur qui est une mauvaise chose.

Mais il y a aussi des problèmes de surcharge d'opérateur tels que définis en C++. Parce que les opérateurs surchargés ne sont que du sucre syntaxique pour les appels de méthode, ils se comportent comme la méthode. D'un autre côté, les opérateurs intégrés normaux ne se comportent pas comme des méthodes. Ces incohérences peuvent être à l'origine de problèmes.

Du haut de ma tête, les opérateurs || et &&.
Les versions intégrées de ceux-ci sont des opérateurs de raccourci. Cela n'est pas vrai pour les versions surchargées et a provoqué certains problèmes.

Le fait que + - */retournent tous le même type sur lequel ils opèrent (après promotion de l'opérateur)
.

8
Martin York

La surcharge de l'opérateur n'est pas quelque chose dont vous avez vraiment besoin très souvent, mais lorsque vous utilisez Java, si vous atteignez un point où vous en avez vraiment besoin, cela vous donnera envie de vous arracher les ongles juste pour avoir une excuse pour arrêter de taper .

Ce code que vous venez de trouver déborde depuis longtemps? Ouaip, vous allez devoir retaper le tout pour le faire fonctionner avec BigInteger. Il n'y a rien de plus frustrant que d'avoir à réinventer la roue juste pour changer le type d'une variable.

7
Steve Thomas

Guy Steele a fait valoir que la surcharge des opérateurs devrait être en Java également, dans son discours d'ouverture "Cultiver un langage" - il y a une vidéo et une transcription de celle-ci, et c'est vraiment un discours incroyable. Je me demande de quoi il parle pour les deux premières pages, mais si vous continuez à lire, vous verrez le point et atteindrez les Lumières. Et le fait même qu'il puisse faire un tel discours est également étonnant.

En même temps, cet exposé a inspiré de nombreuses recherches fondamentales, y compris probablement Scala - c'est l'un de ces articles que tout le monde devrait lire pour travailler dans le domaine.

Pour en revenir au point, ses exemples concernent principalement les classes numériques (comme BigInteger et certaines choses plus étranges), mais ce n'est pas essentiel.

Il est vrai, cependant, qu'une mauvaise utilisation de la surcharge des opérateurs peut conduire à des résultats terribles et que même des utilisations appropriées peuvent compliquer les choses, si vous essayez de lire du code sans étudier un peu les bibliothèques qu'il utilise. Mais est-ce une bonne idée? OTOH, ces bibliothèques ne devraient-elles pas essayer d'inclure une feuille de triche pour leurs opérateurs?

6
Blaisorblade

Je crois que CHAQUE réponse a raté cela. En C++, vous pouvez surcharger les opérateurs comme vous le souhaitez, mais vous ne pouvez pas affecter la priorité avec laquelle ils sont évalués. Scala n'a pas ce problème, IIRC.

Quant à l'idée d'être une mauvaise idée, outre les problèmes de priorité, les gens trouvent des significations vraiment stupides pour les opérateurs, et cela facilite rarement la lisibilité. Scala sont particulièrement mauvaises pour cela, des symboles loufoques que vous devez mémoriser à chaque fois, les responsables de bibliothèque collant la tête dans le sable en disant: "vous n'avez besoin de l'apprendre qu'une seule fois". Génial, maintenant J'ai besoin d'apprendre la syntaxe cryptique d'un auteur "intelligent" * le nombre de bibliothèques que je veux utiliser. Ce ne serait pas si mal s'il existait TOUJOURS une convention fournissant toujours une version alphabétisée des opérateurs.

4
Saem

La seule chose connue mal en C++ est le manque de capacité à surcharger [] = en tant qu'opérateur séparé. Cela pourrait être difficile à implémenter dans un compilateur C++ pour ce qui n'est probablement pas une raison évidente mais en vaut la peine.

3
Joshua

La surcharge des opérateurs n'était pas une invention C++ - elle venait d'ALGOL IIRC et même Gosling ne prétend pas que c'est une mauvaise idée en général.

3
Nemanja Trifunovic

Je n'ai jamais vu un article affirmant que la surcharge d'opérateur de C++ est mauvaise.

Les opérateurs définissables par l'utilisateur permettent un niveau plus élevé d'expressivité et de facilité d'utilisation pour les utilisateurs de la langue.

2
Paul Nathan

Comme les autres réponses l'ont souligné; la surcharge de l'opérateur n'est pas nécessairement mauvaise. Ce qui est mauvais quand il est utilisé de manière à rendre le code résultant peu évident. Généralement, lorsque vous les utilisez, vous devez leur faire faire la chose la moins surprenante (avoir opérateur + faire la division causerait des problèmes pour l'utilisation d'une classe rationnelle) ou comme le dit Scott Meyers:

Les clients savent déjà comment les types comme int se comportent, vous devez donc vous efforcer de faire en sorte que vos types se comportent de la même manière chaque fois que cela est raisonnable ... En cas de doute, faites comme les ints . (De l'article 18 de la 3e édition de C++ efficace)

Maintenant, certaines personnes ont poussé la surcharge des opérateurs à l'extrême avec des choses comme boost :: spirit . À ce niveau, vous n'avez aucune idée de la façon dont il est implémenté, mais cela crée une syntaxe intéressante pour obtenir ce que vous voulez faire. Je ne sais pas si c'est bon ou mauvais. Ça a l'air sympa, mais je ne l'ai pas utilisé.

2
Matt Price

Cependant, il ne semble pas être qualitativement différent de la surcharge d'opérateur en C++, où, si je me souviens bien, les opérateurs sont définis comme des fonctions spéciales.

AFAIK, Il n'y a rien de spécial dans les fonctions opérateur par rapport aux fonctions membres "normales". Bien sûr, vous ne disposez que d'un certain ensemble d'opérateurs que vous pouvez surcharger, mais cela ne les rend pas très spéciaux.

1
John Smith