Что делает оператор Scala перегруженным "хорошо", но C++"плохо"?


перегрузка операторов в C++ считается многими плохой вещью (tm), и ошибка не должна повторяться в новых языках. Конечно, это была одна особенность, специально упавшая при разработке Java.

теперь, когда я начал читать на Scala, я обнаружил, что у него есть то, что очень похоже на перегрузку операторов (хотя технически у него нет перегрузки операторов, потому что у него нет операторов, только функции). Однако, казалось бы, не качественно отличается от перегрузки операторов в C++, где, как я помню, операторы определяются как специальные функции.

Итак, мой вопрос в том, что делает идею определения "+" в Scala лучшей идеей, чем это было в C++?

14 152

14 ответов:

C++ наследует истинные синие операторы от C. Под этим я подразумеваю, что "+" в 6 + 4 очень особенный. Вы не можете, например, получить указатель на эту функцию+.

Scala, с другой стороны, не имеет операторов таким образом. Он просто имеет большую гибкость в определении имен методов плюс немного встроенного приоритета для несловесных символов. Таким образом, технически Scala не имеет перегрузки оператора.

независимо от того, что вы хотите назвать его, перегрузка оператора не является по своей сути плохо, даже в C++. Проблема в том, что плохие программисты злоупотребляют этим. Но, честно говоря, я придерживаюсь мнения, что лишение программистов возможности злоупотреблять перегрузкой оператора не ставит каплю в ведро исправления всех вещей, которые могут злоупотреблять программисты. Настоящий ответ-наставничество. http://james-iry.blogspot.com/2009/03/operator-overloading-ad-absurdum.html

тем не менее, существуют различия между перегрузкой оператора C++и гибким методом Scala называние которого, ИМХО, делает Scala как менее простительным, так и более простительным.

в C++ единственный способ получить нотацию in-fix - это использовать операторы. В противном случае вы должны использовать объект.сообщение (аргумент) или указатель->messsage(аргумент) или функция(argument1, argument2). Поэтому, если вам нужен определенный стиль DSLish для вашего кода, то есть давление на использование операторов.

в Scala вы можете получить инфиксную нотацию с любым отправленным сообщением. "аргумент сообщения объекта" совершенно в порядке, что означает, что вы этого не делаете нужно использовать несловесные символы только для получения инфиксной нотации.

перегрузка операторов C++ ограничена по существу операторами C. В сочетании с ограничением, что только операторы могут быть использованы инфикс, который оказывает давление на людей, чтобы попытаться отобразить широкий спектр несвязанных понятий на относительно небольшое количество символов, таких как "+" и ">>"

Скала позволяет огромный спектр допустимых слов-символов в качестве имен методов. Например, у меня есть встроенный Пролог-ish DSL, где вы можете писать

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 : -, !, ? и и символы определяются как обычные методы. В C++ только & будет действительным, поэтому попытка сопоставить этот DSL в C++ потребует некоторых символов, которые уже вызывают очень разные понятия.

конечно, это также открывает Scala для другого рода злоупотреблений. В Scala вы можете назвать метод $!& ^ % , если вы хотите.

для других языков, которые, как и Scala, являются гибкими в использовании имен функций и методов без слов см. Smalltalk где, как и Scala, каждый "оператор" - это просто другой метод и Haskell, который позволяет программисту определять приоритет и фиксированность гибко именованных функций.

перегрузка операторов в C++ по мнению многих, чтобы быть плохим Вещь(ТМ)

только невежды. Это абсолютно необходимо в таком языке, как C++, и заметно, что другие языки, которые начали принимать "пуристский" вид, добавили его, как только их дизайнеры узнали, насколько это необходимо.

перегрузка операторов никогда не считалась плохой идеей в C++ - просто злоупотребление перегрузкой операторов считалось плохой идеей. На самом деле не нужно перегружать оператор на языке, так как они могут быть смоделированы с более подробными вызовами функций в любом случае. Избегание перегрузки операторов в Java сделало реализацию и спецификацию Java немного проще, и это заставило программистов не злоупотреблять операторами. В сообществе Java были некоторые дебаты по поводу представляем перегрузку оператора.

преимущества и недостатки перегрузки операторов в Scala такие же, как и в C++ - вы можете написать более естественный код, если вы используете перегрузку операторов соответствующим образом - и более загадочный, запутанный код, если вы этого не делаете.

FYI: операторы не определяются как специальные функции в C++, они ведут себя так же, как и любая другая функция - хотя есть некоторые различия в поиске имени, должны ли они быть функциями-членами, и факт что они могут быть вызваны двумя способами: 1) синтаксис оператора и 2) синтаксис operator-function-id.

в этой статье - " положительное наследие C++ и Java" - отвечает на ваш вопрос напрямую.

"C++ имеет как распределение стека, так и распределение кучи, и вы должны перегружать свои операторы, чтобы обрабатывать все ситуации и не вызывать утечки памяти. Действительно трудно. Java, однако, имеет единый механизм распределения памяти и сборщик мусора, что делает перегрузку оператора тривиальной" ...

Java ошибочно (по мнению автора) опущена перегрузка оператора, потому что это было сложно в C++, но забыл почему (или не понял, что это не относится к Java).

к счастью, языки более высокого уровня, такие как Scala, дают разработчикам варианты, все еще работая на той же JVM.

нет ничего плохого в перегрузку операторов. В самом деле, что-то не так с не имея перегрузку оператора для числовых типов. (Взгляните на некоторый код Java, который использует BigInteger и BigDecimal.)

У C++ есть традиция злоупотреблять этой функцией. Часто приводимый пример заключается в том, что операторы bitshift перегружены для выполнения ввода-вывода

в целом это не плохо.
Новые языки, такие как C# также есть перегрузка операторов.

это злоупотребление перегрузкой оператора, что является плохой вещью.

но есть и проблемы с перегрузкой оператора, как определено в C++. Поскольку перегруженные операторы являются просто синтаксическим сахаром для вызовов методов, они ведут себя так же, как метод. С другой стороны, обычные встроенные операторы не ведут себя как методы. Эти несоответствия могут быть причиной проблемы.

С верхней части моей головы операторов || и &&.
Встроенные версии этих операторов являются короткозамкнутыми. Это не верно для перегруженных версий и вызвало некоторые проблемы.

тот факт, что + - * / все возвращают тот же тип, на котором они работают (после продвижения оператора)
Перегруженные версии могут возвращать что угодно (именно здесь происходит злоупотребление, если ваши операторы начинают возвращать какой-то тип арбитра, которого пользователь не ожидал все идет под гору).

перегрузка оператора-это не то, что вам действительно "нужно" очень часто, но при использовании Java, если вы попали в точку, где вам действительно это нужно, это заставит вас захотеть вырвать ногти, чтобы у вас был повод прекратить печатать.

этот код, который вы только что нашли переполняется долго? Да, вам придется перепечатать все, чтобы заставить его работать с BigInteger. Нет ничего более разочаровывающего в том, что нужно изобретать колесо, чтобы просто изменить тип a переменная.

Гай Стил утверждал, что перегрузка оператора должна быть и на Java, в своей основной речи "выращивание языка" - есть видео и транскрипция его, и это действительно потрясающая речь. Вы будете задаваться вопросом, о чем он говорит на первых двух страницах, но если вы продолжите читать, вы увидите смысл и достигнете просветления. И сам факт, что он вообще смог произнести такую речь, тоже поражает.

в то же время эти разговоры вдохновляют фундаментальные исследования, возможно, в том числе и Scala - это одна из тех работ, которые каждый должен прочитать, чтобы работать в этой области.

возвращаясь к сути, его примеры в основном касаются числовых классов (например, BigInteger и некоторые более странные вещи), но это не важно.

Это правда, что неправильное использование перегрузки оператора может привести к ужасным результатам, и что даже правильное использование может усложнить дело, если вы попытаетесь прочитать код, не изучая немного библиотеки, которые он использует. Но разве это хорошая идея? OTOH, не должны ли такие библиотеки пытаться включить операторную шпаргалку для своих операторов?

перегрузка оператора не была изобретением C++ - она пришла из Algol IIRC и даже Гослинг не утверждает, что это плохая идея в целом.

Я считаю, что каждый ответ пропустил это. В C++ вы можете перегружать операторы все, что хотите, но вы не можете влиять на приоритет, с которым они оцениваются. У Scala нет этой проблемы, IIRC.

Что касается того, что это плохая идея, помимо вопросов приоритета, люди придумывают действительно глупые значения для операторов, и это редко помогает читаемости. Библиотеки Scala особенно плохи для этого, глупые символы, которые вы должны запоминать каждый раз, когда сопровождающие библиотеки вставляют свои головы песок говорит: "тебе нужно научиться этому только один раз". Отлично, теперь мне нужно изучить какой-то "умный" авторский загадочный синтаксис * количество библиотек, которые я хочу использовать. Это было бы не так плохо, если бы существовала конвенция всегда поставлять грамотную версию операторов.

единственная известная ошибка в C++ - это отсутствие возможности перегрузки []= как отдельного оператора. Это может быть трудно реализовать в компиляторе C++, что, вероятно, не является очевидной причиной, но стоит того.

как указывали другие ответы; перегрузка оператора сама по себе не обязательно плоха. Что плохо, когда он используется таким образом, что делает полученный код неочевидным. Как правило, при их использовании вам нужно заставить их делать наименее удивительную вещь (наличие оператора + Do division вызовет проблемы для использования рационального класса) или, как говорит Скотт Мейерс:

клиенты уже знают, как такие типы, как инт вести себя, так что вы должны стремиться пусть ваши типы ведут себя в одинаково когда это разумно... когда в сомневаюсь, делай как Инты. (Из действующего пункта 18 3-го издания C++)

теперь некоторые люди взяли перегрузку оператора до крайности с такими вещами, как boost:: spirit. На этом уровне вы понятия не имеете, как это реализовано, но это делает интересный синтаксис, чтобы получить то, что вы хотите сделать. Я не уверен, хорошо это или плохо. Это кажется хорошим, но я не использовал его.

Я никогда не видел статьи, утверждающей, что перегрузка оператора C++плохая.

определяемые пользователем операторы позволяют более легкий более высокий уровень выразительности и удобства использования для пользователей языка.

однако это не будет качественно отличаться от перегрузки оператора в C++, где, как я помню, операторы определяются как специальные функции.

AFAIK, нет ничего особенного в операторных функциях по сравнению с" нормальными " функциями-членами. Конечно, у вас есть только определенный набор операторов, которые можно перегрузить, но это не делает их особенными.