Методы Magi c на других языках программирования - PullRequest
0 голосов
/ 12 марта 2020

Python имеет такие методы, как __add__, __mul__, __cmp__ и т. Д. (Называемые маги c методы ), которые используются в качестве методов класса и могут дать различное значение для добавления (+), умножения (*), сравнения (==), ... двух экземпляров класса. Мой вопрос: есть ли у других языков аналогичный метод? Я знаком с Java, C ++, ruby и PHP, но никогда не сталкивался с таким. Я знаю, что у всех четырех есть метод конструктора, который соответствует __init__, но как насчет других методов волхвов c?

Я пробовал гуглить "методы волхвов c в других языках программирования", но ничего связанного не обнаружилось Возможно, они получили разные имена на разных языках.

Ответы [ 2 ]

4 голосов
/ 12 марта 2020

В общем, наличие слишком большого количества «волшебников» c в языке является признаком плохого языкового дизайна. Может быть, поэтому не так много языков, которые имеют методы magi c?

Magi c, как это создает двухклассовую систему: разработчик языка может добавлять новые методы magi c к языку , но программист может использовать только те методы, которые им позволяет High Priest Of Language Design. В общем, программист должен иметь возможность делать как можно больше без , требующего изменения спецификации языка.

Например, в Scala, +, - , *, /, ==, !=, <, >, <=, >=, ::, |, &, ||, &&, **, ^, +=, -=, *=, /= и т. Д. И т. Д. Являются просто допустимыми идентификаторами. Итак, если вы хотите реализовать свою собственную версию умножения для ваших собственных объектов, вы просто пишете метод с именем *. Это просто скучный старый стандартный метод, в нем нет абсолютно ничего "магического" c.

И наоборот, любой метод может быть вызван с использованием операторной нотации, то есть без точки. И любой метод, который принимает ровно один аргумент, может быть вызван без скобок в нотации оператора.

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

class ↔️[A, B]

, я могу сделать

class Foo extends (String ↔️ Int)

, что аналогично

class Foo extends ↔️[String, Int]

Ну ... я вроде соврал: в Scala есть немного синтаксиса c сахара:

  • foo() переводится в foo.apply(), если нет метода с именем foo по объему. Это позволяет эффективно перегрузить оператор вызова функции.
  • foo.bar = baz переводится в foo.bar_=(baz). Это позволяет эффективно перегружать присваивание свойств. (Это то, как вы пишете сеттеры в Scala.)
  • foo(bar) = baz переводится в foo.update(bar, baz). Это позволяет эффективно перегружать назначение индекса. (Это, например, способ записи массива или словаря в Scala, например.)
  • !foo (и несколько других) переводятся в foo.unary_!.
  • foo += bar попытается вызвать += метод foo, т.е. он эквивалентен foo.+=(bar). Но если это не удастся и foo является допустимым значением lvalue, и foo имеет метод с именем +, тогда Scala также попытается foo = foo + bar.

Кроме того, приоритет, ассоциативность и фиксированность зафиксированы в Scala: они определяются первым символом имени метода. Т.е. все методы, начинающиеся с *, имеют одинаковый приоритет, все методы, начинающиеся с -, имеют одинаковый приоритет и т. Д.

Haskell идет на шаг дальше: * фундаментальный Разница между функциями и операторами. Любая функция может использоваться в нотации вызова функции и в нотации оператора. Единственное отличие - лексическое: если имя функции состоит из символов оператора, тогда, когда я хочу использовать его в нотации вызова функции, я должен заключить его в скобки. OTOH, если имя функции состоит из букв alphanumeri c и я хочу использовать его в нотации оператора, мне нужно обернуть его в кавычки. Итак, следующие значения эквивалентны:

a + b
(+) a b

a `plus` b
plus a b

Для использования оператором функций вы можете свободно определять фиксированность, ассоциативность и приоритет, например:

infixr 15 <!==!>

In Ruby, существует заранее определенный набор операторов, который имеет соответствующие методы, например:

def +(other)
  plus(other)
end
2 голосов
/ 12 марта 2020

В C++ перегрузка оператора - это то, что вы ищете.

Java не имеет встроенной поддержки перегрузки операторов ( ссылка ).

C не имеет перегрузки операторов ( ссылка ). Таким образом, написано много функций add, mult и так далее. Часто это макросы, потому что тогда они могут быть использованы для разных типов. IMHO, именно поэтому мне больше нравится C ++.

@ Алекс дал ссылку на хороший обзор наложения операторов.

...