Qu'est-ce qui fait que L'opérateur de Scala surcharge "bon", mais c++'est "mauvais"?
la surcharge de L'opérateur 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. Certainement, 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 à la surcharge de l'opérateur (bien que techniquement il n'a pas la surcharge de l'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 de l'opérateur en C++, où je me souviens que les opérateurs sont définis comme des fonctions spéciales.
alors ma question Est de savoir pourquoi l'idée de définir " + " en Scala est meilleure qu'en C++?
14 réponses
c++ hérite de vrais opérateurs bleus de C. par cela je veux dire que le "+" en 6 + 4 est très spécial. Vous ne pouvez pas, par exemple, d'avoir un pointeur vers cette fonction.
Scala d'un autre côté 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 plus un peu de construit dans la priorité pour les symboles non-mot. Donc techniquement, Scala n'a pas de surcharge de l'opérateur.
quel que soit le nom que vous voulez lui donner, opérateur la surcharge n'est pas forcément mauvaise, même en C++. Le problème est que les mauvais programmeurs en abusent. Mais franchement, je suis d'avis qu'enlever la capacité des programmeurs d'abuser de la surcharge de l'opérateur ne met pas une goutte dans le seau de réparer toutes les choses 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 y a des différences entre C++'s la surcharge de l'opérateur et la méthode flexible de nom de Scala qui, IMHO, rendent Scala à la fois moins exploitable et plus exploitable.
en C++ la seule façon d'obtenir la notation in-fix est d'utiliser des opérateurs. Sinon, vous devez utiliser l'objet.message (argument) ou pointeur->message(argument) ou fonction(argument1, argument2). Donc, si vous voulez un certain style DSLish à votre code, il y a une pression pour utiliser les opérateurs.
en Scala vous pouvez obtenir la notation infix avec n'importe quel message envoyer. "argument de message objet" est parfaitement ok, ce qui signifie que vous n'avez pas besoin d'utiliser des symboles non-word juste pour obtenir la notation infix.
C++ surcharge d'opérateur est limitée essentiellement à la C les opérateurs. Combiné à la limitation que seuls les opérateurs peuvent être utilisés infix qui met la pression sur les gens pour essayer de cartographier un large éventail de concepts non liés sur un relativement peu de symboles comme " + " et "> > "
Scala permet un large éventail de symboles non-word valides comme les noms de méthode. Par exemple, J'ai un Prolog-ish DSL 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
The: -,!, ? et et symboles sont définis comme les méthodes ordinaires. En C++ seulement & serait valide donc une tentative de mapper cette DSL en C++ nécessiterait quelques symboles qui évoquent déjà des concepts très différents.
bien sûr, cela ouvre aussi Scala à un autre type d'abus. Dans Scala, vous pouvez nommer une méthode $!&^% si vous le souhaitez.
pour les autres langues qui, comme Scala, sont flexibles dans l'utilisation de la fonction non-mot et les noms de méthode voir Smalltalk où, comme Scala, chaque" opérateur " est juste une autre méthode et Haskell qui permet au programmeur de définir la priorité et la fixité des fonctions nommées de manière flexible.
la surcharge de L'opérateur en C++ est considéré par beaucoup comme Un Mauvais Thing (tm)
seulement par les ignorants. Il est absolument nécessaire dans un langage comme C++, et il est à noter que d'autres langues qui ont commencé à adopter une vue "puriste", l'ont ajouté une fois que leurs concepteurs ont découvert à quel point il est nécessaire.
la surcharge de L'opérateur N'a jamais été universellement considérée comme une mauvaise idée en C++ - juste l'abus de la surcharge de l'opérateur a été considérée comme une mauvaise idée. On n'a pas vraiment besoin de surcharger un opérateur dans une langue car ils peuvent être simulés avec plus d'appels de fonction verbeux de toute façon. Éviter la surcharge des opérateurs en Java a rendu l'implémentation et la spécification de Java un peu plus simple et a forcé les programmeurs à ne pas abuser des opérateurs. Il y a eu un certain débat dans la communauté Java à propos de l'introduction de la surcharge d'opérateur.
les avantages et les inconvénients de la surcharge de l'opérateur dans Scala sont les mêmes que dans C++ - vous pouvez écrire plus de code naturel si vous utilisez la surcharge de l'opérateur de manière appropriée - et plus cryptique, code obscurci si vous ne le faites pas.
FYI: les opérateurs ne sont pas définis comme des fonctions spéciales dans C++, ils se comportent comme n'importe quelle autre fonction - bien qu'il y ait quelques différences dans la recherche de nom, si elles doivent être les fonctions de membre, et le fait qu'elles peuvent être appelées de deux façons: 1) syntaxe d'opérateur, et 2) syntaxe opérateur-fonction-id.
cet article - " L'héritage positif de C++ et Java " - répond directement à votre question.
" C++ A à la fois l'allocation de pile et l'allocation de tas et vous devez surcharger vos opérateurs pour gérer toutes les situations et ne pas causer de fuites de mémoire. Difficile, en effet. Java, cependant, a un mécanisme d'allocation de stockage unique et un collecteur de déchets, ce qui rend la surcharge de l'opérateur triviale" ...
Java a omis par erreur (selon l'auteur) la surcharge de l'opérateur car elle était compliquée en C++, mais a oublié pourquoi (ou n'a pas réalisé qu'elle ne s'appliquait pas à Java).
heureusement, les langages de haut niveau comme Scala offrent des options aux développeurs, tout en continuant à fonctionner sur la même JVM.
il n'y a rien de mal à surcharger l'opérateur. En fait, il y a quelque chose qui ne va pas avec et non avec la surcharge de l'opérateur pour les types numériques. (Jetez un coup d'oeil à un code Java qui utilise BigInteger et BigDecimal.)
C++ a une tradition d'abus du trait, cependant. Un exemple souvent cité est que les opérateurs de bitshift sont surchargés pour faire des I/O.
En général, il n'est pas une mauvaise chose.
Les nouveaux langages comme C# ont aussi la surcharge de l'opérateur.
C'est l'abus de la surcharge d'opérateur qui est une mauvaise chose.
mais il y a aussi des problèmes avec la surcharge de l'opérateur comme défini dans C++. Parce que les opérateurs surchargés ne sont que du sucre syntaxique pour les appels de méthodes, ils se comportent comme des méthodes. D'autre part normale intégré opérateurs ne se comportent pas comme des méthodes. Ils l'incohérence peut causer des problèmes.
sur le dessus de ma tête opérateurs ||
et &&
.
Les versions intégrées de ceux-ci sont des opérateurs courts. Ce n'est pas vrai pour les versions surchargées et a causé certains problèmes.
le fait que + - * / tous retournent le même type qu'ils exploitent (après promotion de l'opérateur)
Les versions surchargées peuvent renvoyer n'importe quoi (C'est là que le l'abus s'installe, si vos opérateurs commencent à retourner un certain type d'arbitre l'utilisateur ne s'attendait pas à ce que les choses descendent la colline).
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 longtemps? Tu vas devoir retaper tout ça pour que ça marche avec BigInteger. Il n'y a rien de plus frustrant que d'avoir à réinventer la roue pour changer les le type d'une variable.
Guy Steele a fait valoir que la surcharge de l'opérateur devrait être aussi en Java, dans son discours principal "Growing a language" - Il ya une vidéo et une transcription de celui-ci, et il est vraiment un discours étonnant. Vous vous demanderez de quoi il parle pour les deux premières pages, mais si vous continuez à lire, vous verrez le point et obtiendrez l'illumination. Et le fait qu'il ne pouvait faire un tel discours est aussi incroyable.
en même temps, cette conférence a inspiré une beaucoup de recherche fondamentale, y compris probablement Scala - c'est l'un de ces documents que tout le monde devrait lire pour travailler dans le domaine.
retour au point, ses exemples sont principalement sur les classes numériques (comme BigInteger, et certains trucs plus bizarres), mais ce n'est pas essentiel.
il est vrai, cependant, que l'abus de la surcharge de l'opérateur peut conduire à des résultats terribles, et que même des utilisations appropriées peuvent compliquer les choses, si vous essayez de lire le code sans étudier un peu les bibliothèques qu'il utilise. Mais est-ce une bonne idée? OTOH, de telles bibliothèques ne devraient-elles pas essayer d'inclure une feuille de tricherie pour leurs opérateurs?
la surcharge de L'opérateur N'était pas une invention C++ - elle provenait D'Algol IIRC et même Gosling ne prétend pas que c'est une mauvaise idée en général.
je crois que toutes les réponses ont manqué ça. En C++ , vous pouvez surcharger les opérateurs autant que vous voulez, mais vous ne pouvez pas affecter la priorité avec laquelle ils sont évalués. Scala n'a pas ce problème, IIRC.
pour ce qui est d'une mauvaise idée, outre les questions de priorité, les gens viennent avec des significations vraiment débiles pour les opérateurs, et il aide rarement la lisibilité. Les bibliothèques Scala sont particulièrement mauvaises pour cela, des symboles dingues que vous devez mémoriser à chaque fois, avec les responsables de bibliothèques coller leurs têtes dans le sable disant, 'Vous n'avez besoin de l'apprendre qu'une fois'. Super, maintenant j'ai besoin d'apprendre la syntaxe cryptique d'un auteur "intelligent" * le nombre de bibliothèques que j'ai envie d'utiliser. Ce ne serait pas si mal s'il existait une convention de toujours fournir une version alphabétisée des opérateurs.
la seule erreur connue en c++ est l'absence de capacité de surcharge []= 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 qui en vaut la peine.
comme les autres réponses l'ont fait remarquer; 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 non évident. En général, quand vous les utilisez, vous devez les faire faire la chose la moins surprenante (avoir la division operator+ do causerait des problèmes pour l'usage d'une classe rationnelle) ou comme le dit Scott Meyers:
les Clients savent déjà comment les types comme int se comporter, donc vous devriez vous efforcer de votre les types se comportent de la même façon chaque fois que raisonnable... quand en le doute, faites comme les services de renseignements ne . (Tiré de la 3e édition de C++ Effective, point 18)
maintenant, certaines personnes ont pris la surcharge opérateur à l'extrême avec des choses comme boost::spirit . À ce niveau, vous n'avez aucune idée de comment il est mis en œuvre, mais il fait une syntaxe intéressante pour obtenir ce que vous voulez faire. Je ne sais pas si cela est bon ou mauvais. Il semble bien, mais je n'avez pas utilisé il.
Je n'ai jamais vu un article affirmant que la surcharge de l'opérateur C++est mauvaise.
les opérateurs définissables par L'utilisateur permettent un niveau plus élevé d'expressivité et de convivialité pour les utilisateurs de la langue.
cependant, il ne semble pas être qualitativement différent de la surcharge de l'opérateur en C++, où les opérateurs sont définis comme des fonctions spéciales.
AFAIK, il n'y a rien de spécial dans les fonctions de l'opérateur par rapport aux fonctions "normales" des membres. Bien sûr, vous n'avez qu'un certain nombre d'opérateurs que vous pouvez surcharger, mais cela ne les rend pas très spéciaux.