Что делает перегрузку оператора Scala "хорошим", но С++ "плохой"?

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

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

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

Ответ 1

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

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

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

Тем не менее, существуют различия между перегрузкой оператора С++ и гибким именем метода Scala, которое, IMHO, делает Scala как менее злоупотребляющим, так и более непримиримым.

В С++ единственным способом получить вставку с исправлением является использование операторов. В противном случае вы должны использовать object.message(аргумент) или pointer- > messsage (аргумент) или функцию (аргумент1, аргумент2). Поэтому, если вам нужен определенный стиль DSLish для вашего кода, тогда есть давление на использование операторов.

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

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

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

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

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

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

Символы: -,!,?, и и обозначаются как обычные методы. В С++ только и было бы правильным, поэтому попытка сопоставить этот DSL в С++ потребует некоторых символов, которые уже вызывают очень разные понятия.

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

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

Ответ 2

Перегрузка оператора на С++ которые многие считают Плохо Вещь (TM)

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

Ответ 3

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

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

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

Ответ 4

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

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

Ошибка Java (по словам автора) опустила перегрузку оператора, поскольку она была сложной в С++, но забыла почему (или не понимала, что она не применима к Java).

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

Ответ 5

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

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

Ответ 6

В общем, это не плохо.
Новые языки, такие как С#, также имеют перегрузку оператора.

Это злоупотребление перегрузкой оператора - это плохо.

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

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

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

Ответ 7

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

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

Ответ 8

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

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

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

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

Ответ 9

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

Ответ 10

Я верю, КАЖДЫЙ ответ пропустил это. В С++ вы можете перегружать все операторы, но вы не можете использовать приоритет, с которым они были оценены. Scala не имеет этой проблемы, IIRC.

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

Ответ 11

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

Ответ 12

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

Клиенты уже знают, как типы int, поэтому вы должны стремиться ваши типы ведут себя одинаково когда разумно... Когда в сомневайтесь, сделайте, как ints. (Из Эффективного С++ 3rd Edition, пункт 18)

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

Ответ 13

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

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

Ответ 14

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

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