Множественная отправка

Из Википедии, бесплатной энциклопедии

Множественная диспетчеризация или мультиметоды — это особенность некоторых языков программирования , в которых функция или метод могут быть динамически отправлены на основе типа времени выполнения (динамического) или, в более общем случае, некоторого другого атрибута более чем одного из ее аргументов . [1] Это обобщение с единой диспетчеризацией полиморфизма , при котором вызов функции или метода динамически отправляется на основе производного типа объекта, для которого был вызван метод. Множественная диспетчеризация направляет динамическую отправку реализующей функции или методу, используя объединенные характеристики одного или нескольких аргументов.

Понимание отправки [ править ]

Разработчики компьютерного программного обеспечения обычно организуют исходный код в именованные блоки, которые по-разному называются подпрограммами , процедурами, подпрограммами, функциями или методами. Код в функции выполняется путем ее вызова — выполнения фрагмента кода, который ссылается на ее имя . Это временно передает управление вызываемой функции; когда выполнение функции завершено, управление обычно передается обратно инструкции вызывающей стороны , которая следует за ссылкой.

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

В более традиционных, то есть объектно-ориентированных языках программирования с единой диспетчеризацией , при вызове метода ( отправка сообщения в Smalltalk , вызов функции-члена в C++ ) один из его аргументов обрабатывается особым образом и используется для определения того, какой из (потенциально необходимо применить множество) классов методов с таким именем. Во многих языках специальный аргумент обозначается синтаксически; например, в ряде языков программирования специальный аргумент ставится перед точкой при вызове метода: special.method(other, arguments, here), так что lion.sound() будет производить рев, тогда как sparrow.sound() будет издавать чириканье.

Напротив, в языках с множественной отправкой выбранный метод — это просто тот метод, аргументы которого соответствуют номеру и типу вызова функции. Не существует специального аргумента, которому принадлежит функция/метод, выполняемая в конкретном вызове.

Объектная система Common Lisp (CLOS) — ранний и хорошо известный пример множественной диспетчеризации. Еще одним ярким примером использования множественной диспетчеризации является Julia язык программирования .

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

Типы данных [ править ]

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

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

Динамическая диспетчеризация вызовов функций связана с некоторыми затратами во время выполнения. В некоторых языках [ нужна цитата ] различие между перегрузкой и мультиметодами может быть размытым, поскольку компилятор определяет, можно ли применить выбор времени компиляции к данному вызову функции или требуется более медленная диспетчеризация во время выполнения.

Проблемы [ править ]

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

Выразительность и модульность [ править ]

В большинстве популярных языков программирования исходный код поставляется и развертывается в виде функциональных фрагментов, которые мы здесь будем называть пакетами ; фактическая терминология этой концепции варьируется в зависимости от языка. Каждый пакет может содержать несколько определений типа, значения и функции, пакеты часто компилируются отдельно на языках с этапом компиляции, и могут существовать нециклические отношения зависимости. Полная программа — это набор пакетов, главный из которых может зависеть от нескольких других пакетов, а вся программа состоит из транзитивного замыкания отношений зависимости.

Так называемая проблема выражения связана с возможностью кода в зависимом пакете расширять поведение (функции или типы данных), определенные в базовом пакете, из включающего пакета, не изменяя исходный код базового пакета. Традиционные объектно-ориентированные языки с единой диспетчеризацией упрощают добавление новых типов данных, но не новых функций; традиционные функциональные языки имеют тенденцию иметь противоположный эффект, а множественная диспетчеризация, если она реализована правильно, позволяет и то, и другое. Желательно, чтобы реализация множественной диспетчеризации имела следующие свойства:

  • Можно определить разные «случаи» мультиметода из разных пакетов без изменения исходного кода базового пакета.
  • Включение другого пакета в программу не должно изменять поведение данного вызова нескольких методов, если вызов не использует какие-либо типы данных, определенные в пакете.
  • И наоборот, если тип данных определен в данном пакете, а многометодное расширение, использующее этот тип, также определено в том же пакете, и значение этого типа передается (через ссылку на базовый тип или в универсальную функцию) в другой пакет, не зависящий от этого пакета, а затем вызывается мультиметод с этим значением в качестве аргумента, следует использовать случай с несколькими методами, определенный в пакете, который включает этот тип. Другими словами, в рамках данной программы один и тот же мультиметод, вызываемый с одним и тем же набором аргументов, должен разрешаться к одной и той же реализации, независимо от местоположения места вызова и от того, находится ли данное определение «в области видимости». " или "видимый" в момент вызова метода.

Двусмысленность [ править ]

Обычно желательно, чтобы для любого данного вызова мультиметода среди случаев реализации мультиметода был не более одного «лучшего» кандидата, и/или, если такового нет, решить эту проблему предсказуемым и предсказуемым образом. детерминированный способ, включая неудачу. Недетерминированное поведение нежелательно. Предполагая набор типов с нециклической связью подтипов, можно определить, что одна реализация мультиметода является «лучшей» (более конкретной), если все динамически отправляемые аргументы в первом являются подтипами всех указанных динамически отправляемых аргументов. во втором, и по крайней мере один из них является строгим подтипом. При одиночной отправке и отсутствии множественного наследования это условие тривиально выполняется, но при множественной отправке два или более кандидатов могут удовлетворять заданному фактическому списку аргументов, но ни один из них не является более конкретным, чем другой (один динамический аргумент в одном случае это подтип, а в другом — подтип). Это, в частности, может произойти, если два разных пакета, ни один из которых не зависит от другого, расширяют некоторый мультиметод реализациями, относящимися к типам каждого пакета, а затем третий пакет, который включает оба (возможно, косвенно), затем вызывает мультиметод, используя аргументы из обоих. пакеты.

Возможные решения включают в себя:

  • Рассматривать любые неоднозначные вызовы как ошибку. Это может быть обнаружено во время компиляции (или иным образом перед развертыванием), но может не быть обнаружено до времени выполнения и вызвать ошибку времени выполнения.
  • Упорядочение аргументов, например, выбирается случай с наиболее конкретным первым аргументом, а последующие аргументы не учитываются для разрешения неоднозначности, если первый аргумент недостаточен для решения проблемы.
  • Построение других правил разрешения неоднозначности в ту или иную сторону. Иногда такие правила могут быть произвольными и неожиданными. Например, в правилах статического разрешения перегрузки в C++ тип, который точно соответствует, по понятным причинам считается лучшим соответствием, чем тип, который соответствует через ссылку на базовый тип или универсальный параметр (шаблон). Однако если единственные возможные совпадения происходят либо через базовый тип, либо через универсальный параметр, универсальный параметр предпочтительнее базового типа, и это правило иногда приводит к неожиданному поведению.

Эффективность [ править ]

Эффективная реализация единой диспетчеризации, в том числе на языках программирования, которые отдельно компилируются в объектный код и связываются с низкоуровневым (не поддерживающим язык) компоновщиком, в том числе динамически во время загрузки/запуска программы или даже под управлением приложения. код, хорошо известны. Метод " vtable ", разработанный на C++ и других ранних объектно-ориентированных языках (где каждый класс имеет массив указателей функций, соответствующих виртуальным функциям этого класса), почти так же быстр, как вызов статического метода, требуя накладных расходов O(1) и только одного дополнительного поиск в памяти даже в неоптимизированном случае. Однако метод vtable использует имя функции, а не тип аргумента, в качестве ключа поиска и не масштабируется для случая множественной отправки. (Это также зависит от объектно-ориентированной парадигмы методов, которые являются функциями классов, а не отдельными объектами, независимыми от какого-либо конкретного типа данных).

Эффективная реализация множественной диспетчеризации остается постоянной исследовательской проблемой.

Использование на практике [ править ]

Чтобы оценить, как часто на практике используется множественная диспетчеризация, Muschevici et al. [2] изучал программы, использующие динамическую диспетчеризацию. Они проанализировали девять приложений, в основном компиляторов, написанных на шести разных языках: Common Lisp Object System , Dylan , Cecil , MultiJava, Diesel и Nice. Их результаты показывают, что 13–32% универсальных функций используют динамический тип одного аргумента, а 2,7–6,5% из них используют динамический тип нескольких аргументов. Остальные 65–93% универсальных функций имеют один конкретный метод (переопределение) и, следовательно, не считаются использующими динамические типы своих аргументов. Кроме того, в исследовании сообщается, что 2–20% общих функций имели две, а 3–6% имели три реализации конкретных функций. Цифры быстро уменьшаются для функций с более конкретными переопределениями.

Множественная диспетчеризация гораздо более интенсивно используется в Julia , где множественная диспетчеризация была центральной концепцией дизайна с самого начала языка: собрав ту же статистику, что и Мушевичи, о среднем количестве методов на одну обобщенную функцию, было обнаружено, что стандартная библиотека Julia использует количество перегрузок более чем в два раза больше, чем в других языках, проанализированных Мушевичем, и более чем в 10 раз в случае бинарных операторов . [3]

Данные из этих статей сведены в следующую таблицу, где коэффициент отправки DR— среднее количество методов на универсальную функцию; соотношение выбора CR — среднее квадратическое числа методов (чтобы лучше измерить частоту функций с большим количеством методов); [2] [3] и степень специализации DoS — это среднее количество аргументов, специализированных по типу, на метод (т. е. количество аргументов, которые отправляются):

Язык Среднее количество методов (DR) Коэффициент выбора (CR) Степень специализации (DoS)
Сесил [2] 2.33 63.30 1.06
Общий Лисп ( CMU ) [2] 2.03 6.34 1.17
Общий Лисп ( McCLIM ) [2] 2.32 15.43 1.17
Common Lisp ( Стальной банк ) [2] 2.37 26.57 1.11
Дизель [2] 2.07 31.65 0.71
Дилан (Гвидион) [2] 1.74 18.27 2.14
Дилан (OpenDylan) [2] 2.51 43.84 1.23
Юлия [3] 5.86 51.44 1.54
Юлия (только операторы) [3] 28.13 78.06 2.01
МультиЯва [2] 1.50 8.92 1.02
Хороший [2] 1.36 3.46 0.33

Теория [ править ]

Теория множественных языков диспетчеризации была впервые разработана Кастанья и др. путем определения модели перегруженных функций с поздним связыванием . [4] [5] Это привело к первой формализации проблемы ковариантности и контравариантности объектно-ориентированных языков. [6] и решение проблемы бинарных методов. [7]

Примеры [ править ]

Различие многократной и однократной отправки можно прояснить на примере. Представьте себе игру, в которой среди (видимых пользователем) объектов есть космические корабли и астероиды. Когда два объекта сталкиваются, программе может потребоваться выполнить разные действия в зависимости от того, что с чем только что столкнулось.

Языки со встроенной множественной отправкой [ править ]

С# [ править ]

В C# появилась поддержка динамических мультиметодов в версии 4. [8] (апрель 2010 г.) с использованием ключевого слова «динамический». В следующем примере демонстрируются мультиметоды. Как и многие другие статически типизированные языки, C# также поддерживает перегрузку статических методов. [9] Microsoft ожидает, что в большинстве сценариев разработчики предпочтут статическую типизацию динамической типизации. [10] Ключевое слово «динамический» поддерживает взаимодействие с COM-объектами и динамически типизированными языками .NET.

В приведенном ниже примере используются функции, представленные в C# 9 и C# 10.

использование   статической   ColliderLibrary  ; 

  Консоль  .   WriteLine  (  Collide  (  новый   астероид  (  101  ),   новый   космический корабль  (  300  ))); 
  Консоль  .   WriteLine  (  Collide  (  новый   астероид  (  10  ),   новый   космический корабль  (  10  ))); 
  Консоль  .   WriteLine  (  Collide  (  новый   космический корабль  (  101  ),   новый   космический корабль  (  10  ))); 

  строка   Столкновение  (  SpaceObject   x  ,   SpaceObject   y  )   => 
     x  .   Размер   >   100   &&   y  .   Размер   >   100 
         ?    «Большой бум!» 
          :   CollideWith  (  x   как   динамический  ,   y   как   динамический  );    // Динамическая отправка методу CollideWith 

 class   ColliderLibrary 
 { 
     public   static   string   CollideWith  (  Asteroid   x  ,   Asteroid   y  )   =>   "a/a"  ; 
      общедоступная   статическая   строка   CollideWith  (  Астероид   x  ,   Космический корабль   y  )   =>   "a/s"  ; 
      public   static   string   CollideWith  (  Космический корабль   x  ,   Астероид   y  )   =>   "s/a"  ; 
      общедоступная   статическая   строка   CollideWith  (  Космический корабль   x  ,   Космический корабль   y  )   =>   "s/s"  ; 
  } 

 абстрактная   запись   SpaceObject  (  int   Size  ); 
  запись   Asteroid  (  int   Size  )   :   SpaceObject  (  Size  ); 
  запись   Космический корабль  (  int   Size  )   :   SpaceObject  (  Size  ); 

Выход:

Большой бум! 
  а/с 
 с/с 

Круто [ править ]

Groovy общего назначения  — это Java -совместимый/взаимоиспользуемый язык JVM , который, в отличие от Java, использует позднее связывание/множественную диспетчеризацию. [11]

/* 
 Groovy-реализация приведенного выше примера C# 
 Позднее связывание работает одинаково при использовании нестатических методов или статической компиляции класса/методов 
 (@CompileStatic annotation) 
 */ 
 class   Program   { 
     static   void   main  (  String  []   args  )   { 
         println   Collider  .   столкновение  (  новый   астероид  (  101  ),   новый   космический корабль  (  300  )) 
         println   Collider  .   столкновение  (  новый   астероид  (  10  ),   новый   космический корабль  (  10  )) 
         println   Collider  .   столкновение  (  новый   космический корабль  (  101  ),   новый   космический корабль  (  10  )) 
     } 
 } 

 class   Collider   { 
     static   String   столкновение  (  SpaceObject   x  ,   SpaceObject   y  )   { 
         (  x  .  size   >   100   &&   y  .  size   >   100  )   ?    "big-boom"   :   collideWith  (  x  ,   y  )    Динамическая отправка методуcollideWith 
     } 

     Private   static   StringcollideWith   StringcollideWith  (  Asteroid   x  ,   Asteroid   y  )   {   /a"   } 
     Private   static   //   " a  (  Asteroid   x  ,   Spaceship   y  )   {   a/s"   } 
     Private   static   StringcollideWith   StringcollideWith  (  Spaceship   x  ,   Asteroid   y  )   {   "   } 
     Private   static   "s/ a   "  (  Spaceship   x  ,   Spaceship   y  )   {   "s/s"  } 
 } 

 class   SpaceObject   { 
     int   size 
     SpaceObject  (  int   размер  )   {   это  .   size   =   size   } 
 } 

 @InheritConstructors   class   Asteroid   расширяет   SpaceObject   {} 
 @InheritConstructors   class   Spaceship   расширяет   SpaceObject   {} 

Общий Лисп [ править ]

В языке с множественной диспетчеризацией, таком как Common Lisp , это может выглядеть примерно так (показан пример Common Lisp):

(  defmethod   столкновение-с   ((  x   астероид  )   (  y   астероид  )) 
   астероида с астероидом 
   ) 
 (  defmethod   столкновение-с   ((  x   астероид  )   (  y   космический корабль  )) 
   ;; справиться с астероидом, столкнувшимся с космическим кораблем 
   ) 
 (  defmethodcollide-   ;; справиться с столкновением  with   ((  x   spaceship  )   (  y   asteroid  )) 
   ;; справиться с столкновением космического корабля с астероидом 
   ) 
 (  defmethodcollide   -with   ((  x   spaceship  )   (  y   spaceship  )) 
   ;; справиться с столкновением космического корабля с космическим кораблем 
   ) 

и аналогично для других методов. Явное тестирование и «динамическое приведение типов» не используются.

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

Юлия [ править ]

В Julia есть встроенная множественная диспетчеризация, и это занимает центральное место в конструкции языка. [3] Версия Джулии приведенного выше примера может выглядеть так:

абстрактный   тип   SpaceObject   end 

 struct   Asteroid   <:   SpaceObject 
     Размер  ::  Int     
 end 
 struct   Spaceship   <:   SpaceObject 
     Размер  ::  Int                   
 endcollide_with 

 "  (  ::  Asteroid  ,   ::  Spaceship  )   =   "a/s 
 collide_with  (  ::  Spaceship  ,   ::  Asteroid  )   =   "s/a" 
 collide_with  (  :  Spaceship  ,   ::  Spaceship  )   =   "s/s" 
 collide_with  (  ::  Asteroid  ,   ::  Asteroid  )   =   "a/a" 

 столкновение  (  x  :  SpaceObject  ,   y  :  SpaceObject  )   =   (  x  .  размер   >   100   &&   y  .  размер   >   100  )   ?    «Большой бум!»    :   collide_with  (  x  ,   y  ) 

Выход:

julia>   collide  (  Астероид  (  101  ),   Космический корабль  (  300  )) 
 "Большой бум!" 

  julia>   collide  (  Астероид  (  10  ),   Космический корабль  (  10  )) 
 "a/s" 

 julia>   collide  (  Космический корабль  (  101  ),   Космический корабль  (  10  )) 
 "s/s" 

Раку [ править ]

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

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

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

подмножество   Mass   of   Real   , где   0  ^..^  Inf  ;  
  роль   Звездный-Объект  { 
      имеет   массу   .mass   Требуется   ;  $ 
      метода   имя  ()  возвращает   Str  {...}; 
  } 
  класс   Астероид   делает   Звездный Объект  { 
      метода   имя  () {  'астероид'  } 
  } 
  класс   Космический корабль   делает   Звездный объект  { 
      has   Str   $.name  =  'какой-то безымянный космический корабль'  ; 
  } 
  my   Str   @destroyed  = <  уничтожено   уничтожено   искалечено  >; 
  my   Str   @damaged  = «  поврежден   «столкнулся с»   «был поврежден»  »; 

  # Мы добавляем несколько кандидатов к операторам числового сравнения, поскольку мы сравниваем их численно, 
 # но нет смысла приводить объекты к числовому типу. 
  # (Если бы они применяли принуждение, нам не обязательно было бы добавлять эти операторы.) 
 # Мы могли бы также определить совершенно новые операторы таким же образом. 
  мульти   -инфикс   :  « <=> » (  Stellar-Object:D   $a  ,  Stellar-Object:D   $b  ) {  $a  .   масса  <=>  $b  .   масса  } 
  мульти   -инфикс   :  « < » (  Stellar-Object:D   $a  ,  Stellar-Object:D   $b  ) {  $a  .   масса  <  $b  .   масса  } 
  мульти   -инфикс   :  « > » (  Stellar-Object:D   $a  ,  Stellar-Object:D   $b  ) {  $a  .   масса  >  $b  .   масса  } 
  мульти   -инфикс   :  « == » (  Stellar-Object:D   $a ,  Звездный объект:D   $b  ) {  $a  .   масса  ==  $b  .   масса  } 

  # Определите новый мультидиспетчер и добавьте к параметрам некоторые ограничения типов. 
  # Если бы мы его не определили, мы бы получили общий вариант без ограничений. 
  протоподстолкновение   Stellar- Object   }  (  :D  $,  Stellar-Object:D  $ ) {* 

  # Здесь нет необходимости повторять типы, поскольку они такие же, как в прототипе. 
  # Технически ограничение «где» применяется только к $b, а не ко всей подписи. 
  # Обратите внимание, что ограничение 'where' использует кандидата на оператор `<`, который мы добавили ранее. 
  множественное   столкновение   $  (  a  ,  $b   где   $a  <  $b  ) { 
      скажем   : «$a.name() был @destroyed.pick() пользователем $b.name()»  ; 
  } 
  множественное   столкновение   $  (  a  ,  $b   где   $a  >  $b  ) { 
      # повторная отправка предыдущему кандидату с заменой аргументов 
     на   $b  ,  $a  ; 
  } 

  # Это должно быть после первых двух, потому что остальные 
 # имеют ограничения "где", которые проверяются в том 
 # порядке, в котором были написаны подпрограммы.   (Этот вариант всегда будет совпадать.) 
 multi   sub   столкновение  (  $a  ,  $b  ) { 
      # рандомизировать порядок 
     my  (  $n1  ,  $n2  ) = (  $a  .  name ,  .   имя  ).   выбирать  (*); 
      скажите   "$n1 @damaged.pick() $n2"  ; 
  } 

  # Следующие два кандидата могут находиться где угодно после прототипа, 
 # потому что они имеют более специализированные типы, чем предыдущие три. 

  # Если корабли имеют неравную массу, вместо этого вызывается один из первых двух кандидатов. 
  множественное   столкновение   где  (  Космический корабль   $a  ,  Космический корабль   $b,   $   a  ==  $b  ){ 
      my  (  $n1  ,  $n2  = (  $  a.name  ,  )  $  b.name  )  .   выбирать  (*); 
      скажем   "$n1 столкнулся с $n2, и оба корабля были "  , 
      (  @destroyed  .  Pick  ,  «осталось поврежденным»  ).   выбирать  ; 
  } 

  # Вы можете распаковать атрибуты в переменные внутри подписи. 
  # Вы могли бы даже установить для них ограничение `(:mass($a)where 10)`. 
  множественное   столкновение   $  (  Астероид  $ (:  масса  (  $a  )),  Астероид  $ (:  масса  (  b  )) ){ 
      скажем   : «два астероида столкнулись и объединились в один больший астероид массой { $a + $b }»  ; 
  } 

  мой   космический корабль   $Enterprise  .=  new  (:  mass  (  1  ),:  name  (  'The Enterprise'  )); 
  столкнуться   с астероидом  .   новый  (:  масса  (  .1  )),  $Enterprise  ; 
  столкновение   $ Enterprise  ,  Космический корабль  .   новый  (:  масса  (  .1  )); 
  столкновение   $Enterprise  ,  Астероид  .   новый  (:  масса  (  1  )); 
  столкнуться   $Enterprise  , Космический корабль  .   новый  (:  масса  (  1  )); 
  столкнуться   с астероидом  .   новый  (:  масса  (  10  )),  Астероид  .   новый  (:  масса  (  5  )); 
 

Расширение языков с помощью библиотек с несколькими диспетчеризациями [ править ]

JavaScript [ править ]

В языках, которые не поддерживают множественную отправку на уровне определения языка или синтаксиса, часто можно добавить множественную отправку с помощью расширения библиотеки . JavaScript и TypeScript не поддерживают мультиметоды на уровне синтаксиса, но можно добавить множественную диспетчеризацию через библиотеку. Например, пакет мультиметодов [12] обеспечивает реализацию нескольких общих функций диспетчеризации.

Динамически типизированная версия на JavaScript:

import   {   multi  ,   метод   }   from   '@arrows/multimethod' 

 class   Asteroid   {} 
 class   Spaceship   {} 

 constcollideWith   // имеем дело с столкновением   =   multi  ( 
   method  ([  Asteroid  ,   Asteroid  ],   (  x  ,   y  )   =>   { 
     астероида с астероидом 
   } ) 
   ;      
    
  
       
     ​астероид 
   }), 
   метод  ([  Космический корабль  ,   Космический корабль  ],   (  x  ,   y  )   =>   { 
     // дело о столкновении космического корабля с космическим кораблем 
   }), 
 ) 

Статически типизированная версия на TypeScript:

import   {   multi  ,   метод  ,   Multi   }   из   '@arrows/multimethod' 

 class   Asteroid   {} 
 class   Spaceship   {} 

 type   CollideWith   =   Multi   &   { 
   (  x  :   Asteroid  ,   y  :   Asteroid  )  :   void 
   (  x  :   Asteroid  ,   y  :   Spaceship  )  :   void 
   (  x  :   Космический корабль  ,   y  :   Астероид  )  :   void 
   (  x  :   Космический корабль  ,   y  :   Космический корабль  )  :   void 
 } 

 const   collideWith  :   CollideWith   =   multi  ( 
   метод  ([  Asteroid  ,   Asteroid  ],   (  x  ,   y  )   =>   { 
     // сделка с столкновением астероида с астероидом 
   }), 
   метод  ([  Астероид  ,   Космический корабль  ],   (  x  ,   y  )   =>   { 
     // имеем дело с столкновением астероида с космическим кораблем 
   }), 
   метод  ([  Космический корабль  ,   Астероид  ],   (  x  ,   y  )   =>   { 
     / / справиться с столкновением космического корабля с астероидом 
   }), 
   метод  ([  Космический корабль  ,   Космический корабль  ],   (  x  ,   y  )   =>   { 
     // справиться с столкновением космического корабля с космическим кораблем 
   }), 
 ) 

Питон [ править ]

Множественную диспетчеризацию можно добавить в Python с помощью расширения библиотеки . Например, используя модуль multimethod.py [13] а также с модулем multimethods.py [14] который предоставляет мультиметоды в стиле CLOS для Python без изменения базового синтаксиса или ключевых слов языка.

из   multimethods   import   Dispatch 
 из   game_objects   import   Asteroid  ,   Spaceship 
 из   game_behaviors   import   as_func  ,   ss_func  ,   sa_funccollide 

 collide   =   Dispatch  ( 
 .  )   add_rule  ((  Астероид  ,   Космический корабль  ),   as_func  ) 
 столкновение  .   add_rule  ((  Космический корабль  ,   Космический корабль  ),   ss_func  ) 
 столкновение  .   add_rule  ((  Spaceship  ,   Asteroid  ),   sa_func  ) 

 def   aa_func  (  a  ,   b  ): 
     """Поведение при столкновении астероида с астероидом.""" 
     # ...определить новое поведение... 

 столкновение  .   add_rule  ((  Астероид  ,   Астероид  ),   aa_func  ) 
# ...позже... 
 столкнуться  (  thing1  ,   thing2  ) 

Функционально это очень похоже на пример CLOS, но синтаксис обычный Python.

Python 2.4 Используя декораторы , Гвидо ван Россум создал пример реализации мультиметодов. [15] с упрощенным синтаксисом:

@multimethod  (  Asteroid  ,   Asteroid  ) 
 def   Collide  (  a  ,   b  ): 
     """Поведение при столкновении астероида с астероидом.""" 
     # ...define new Behavior... 
 @multimethod  (  Asteroid  ,   Spaceship  ) 
 def   Collide  (  a  ,   b  ): 
     """Поведение при столкновении астероида с космическим кораблем.""" 
     # ...определить новое поведение... 
 # ... определить другие правила мультиметода... 

а затем определяется декоратор мультиметода.

Пакет PEAK-Rules обеспечивает множественную диспетчеризацию с синтаксисом, аналогичным приведенному выше примеру. [16] Позже он был заменен PyProtocols. [17]

Библиотека Reg также поддерживает множественную отправку и отправку предикатов. [18]

С появлением подсказок типов возможна множественная отправка с еще более простым синтаксисом. Например, используя Plum-dispatch ,

from   сливовый   импорт   диспетчеризации 

 @dispatch 
 def   Collide  (  a  :   Asteroid  ,   b  :   Asteroid  ): 
     """Поведение при столкновении астероида с астероидом.""" 
     # ...определить новое поведение... 
    
 @dispatch 
 def   Collide  (  a  :   Asteroid  ,   b  :   Космический корабль  ): 
     """Поведение при столкновении астероида с космическим кораблем.""" 
     # ...определить новое поведение... 
    
 # ...определить дальнейшие правила... 

Эмуляция множественной отправки [ править ]

С [ править ]

В языке C нет динамической диспетчеризации, поэтому ее необходимо в той или иной форме реализовать вручную. Часто перечисление используется для идентификации подтипа объекта. Динамическую отправку можно выполнить, найдя это значение в указателя функции таблице ветвей . Вот простой пример на C:

typedef   void   (  *  CollisionCase  )(  void  ); 

  void   columns_AA  (  void  )   {   /* обработка столкновения астероидов с астероидами */   }; 
  void   columns_AS  (  void  )   {   /* обрабатываем столкновение астероида и космического корабля */   }; 
  void   columns_SA  (  void  )   {   /* обработка столкновения космического корабля с астероидом */   }; 
  void   columns_SS  (  void  )   {   /* обработка столкновения космических кораблей с космическими кораблями */   }; 

  typedef   enum   { 
     THING_ASTEROID   =   0  , 
     THING_SPACESHIP  , 
     THING_COUNT   /* не является типом самой вещи, вместо этого используется для поиска количества вещей */ 
 }   Thing  ; 

  CollisionCase   ColombiaCases  [  THING_COUNT  ][  THING_COUNT  ]   =   { 
     {  &  Colombia_AA  ,   &  Collision_AS  }, 
     {  &  Collision_SA  ,   &  Collision_SS  } 
 }; 

  void   Collide  (  Thing   a  ,   Thing   b  )   { 
     (  *  columnsCases  [  a  ][  b  ])(); 
  } 

 Int   Main  (  void  )   { 
     столкновение  (  THING_SPACESHIP  ,   THING_ASTEROID  ); 
  } 

С помощью библиотеки объектной системы C, [19] C поддерживает динамическую отправку, аналогичную CLOS. Он полностью расширяем и не требует ручной обработки методов. Динамические сообщения (методы) отправляются диспетчером COS, который работает быстрее, чем Objective-C. Вот пример в COS:

#include   <stdio.h> 
 #include   <cos/Object.h> 
 #include   <cos/gen/object.h> 

 // классы 

 defclass   (  Asteroid  ) 
 // члены данных 
 endclass 

 defclass   (  Spaceship  ) 
 // члены данных 
 endclass 

 // дженерики 

 defgeneric   (  _Bool  ,   столкновение_с  ,   _1  ,   _2  ); 

  // мультиметоды 

 defmethod   (  _Bool  ,   collide_with  ,   Asteroid  ,   Asteroid  ) 
  // обработка столкновения астероида с астероидом 
 endmethod 

 defmethod   (  _Bool  ,   collide_with  ,   Asteroid  ,   Spaceship  ) 
  // обработка столкновения астероида с космическим кораблем 
 endmethod 

 defmethod   (  _Bool  ,   collide_with  ,   Spaceship  ,   Asteroid  ) 
  / / справиться с столкновением космического корабля с астероидом 
 endmethod 

 defmethod   (  _Bool  ,   collide_with  ,   Spaceship  ,   Spaceship  ) 
  // справиться с столкновением космического корабля с космическим кораблем 
 endmethod 

 // пример использования 

 int   main  (  void  ) 
 { 
   OBJ   a   =   gnew  (  Asteroid  ); 
    OBJ   s   =   gnew  (  Космический корабль  ); 

    printf  (  "<a,a> = %d  \n  "  ,   столкновение_с  (  a  ,   a  )); 
    printf  (  "<a,s> = %d  \n  "  ,   столкновение_с  (  a  ,   s  )); 
    printf  (  "<s,a> = %d  \n  "  ,   столкновение_с  (  s  ,   a  )); 
    printf  (  "<s,s> = %d  \n  "  ,   столкновение_с  (  s  ,   s  )); 

    смазка  (  а  ); 
    смазка  (  а  ); 
  } 

С++ [ править ]

По состоянию на 2021 год изначально C++ поддерживает только одиночную отправку, хотя добавление нескольких методов (множественная диспетчеризация) было предложено Бьярном Страуструпом (и его соавторами) в 2007 году. [20] Методы обхода этого ограничения аналогичны: использовать либо шаблон посетителя , динамическое приведение, либо библиотеку:

 // Пример использования сравнения типов во время выполнения через 

  struct   Thing   { 
      virtual   voidcollideWith   (  &  Thing  Dynamic_cast   other  )   =   0  ; 
   }; 

   struct   Asteroid   :   Thing   { 
      voidcollideWith   // Dynamic_cast к типу указателя возвращает NULL ,  (  Thing  &   other  )   { 
          если приведение не удалось 
          // (dynamic_cast к ссылочному типу вызовет исключение в случае неудачи) 
          if   (  auto   asteroid   =   Dynamic_cast  <  Asteroid  * >  (  &  другие  ))   { 
              // обрабатываем столкновение астероид-астероид 
          }   else   if   (  auto   spaceship   =   Dynamic_cast  <  Spaceship  *>  (  &  Other  ))   { 
              // обрабатываем столкновение астероид-космический корабль 
          }   else   { 
              // здесь обработка столкновений по умолчанию 
          } 
      } 
  }; 

   struct   Spaceship   :   Thing   { 
      voidcollideWith   (  }  Thing  &   other  )   { 
          if   (  auto   asteroid   =   Dynamic_cast  <  Asteroid  *>  (  &  Other  ))   { 
              // обрабатываем столкновение космического корабля с астероидом 
          else   if   (   auto  spaceship   =   Dynamic_cast   <  Spaceship  *  >  (  &  Other  ))   { 
              // обработка столкновения космических кораблей с космическими кораблями 
          }   else   { 
              // здесь обработка столкновений по умолчанию 
          } 
      } 
  }; 

или таблица поиска указателя на метод:

#include   <cstdint> 
 #include   <typeinfo> 
 #include   <unordered_map> 

 class   Thing   { 
   protected  : 
     Thing  (  std  ::  uint32_t   cid  )   :   tid  (  cid  )   {} 
     ​​const   std  ::  uint32_t   tid  ;    // идентификатор типа 

     typedef   void   (  Thing  ::*  CollisionHandler  )(  Thing  &   Other  ); 
      typedef   std  ::  unordered_map  <  std  ::  uint64_t  ,   CollisionHandler  >   CollisionHandlerMap  ; 

      static   void   addHandler  (  std  ::  uint32_t   id1  ,   std  ::  uint32_t   id2  ,   CollisionHandler   обработчик  )   { 
         collisionCases  .   вставить  (  CollisionHandlerMap  ::  value_type  (  ключ  (  id1  ,   id2  ),   обработчик  )); 
      } 
     static   std  ::  uint64_t   key  (  std  ::  uint32_t   id1  ,   std  ::  uint32_t   id2  )   { 
         return   std  ::  uint64_t  (  id1  )   <<   32   |    идентификатор2  ; 
      } 

     Статическая   CollisionHandlerMap   columnsCases  ; 

    public  : 
     void   CollideWith  (  Thing  &   Other  )   { 
         автообработчик    =   columnsCases  .   найти  (  ключ  (  tid  ,   другое  .  tid  )); 
          if   (  обработчик   !=   столкновениеCases  .  end  ())   { 
             (  это  ->*  обработчик  ->  второй  )(  другое  );    // вызов указателя на метод 
         }   else   { 
             // обработка коллизий по умолчанию 
         } 
     } 
 }; 

  class   Asteroid  :   public   Thing   { 
     void   asteroid_collision  (  Thing  &   other  )     {   /*обработка столкновения астероида с астероидом*/   } 
     void   spaceship_collision  (  Thing  &   other  )    {   /*обработка столкновения астероида и космического корабля*/  } 

   public  : 
     Asteroid  ()  :   Thing  (  cid  )   {} 
     static   void   initCases (); 
      static   const   std  ::  uint32_t   cid  ; 
  }; 

  class   Spaceship  :   public   Thing   { 
     void   asteroid_collision  (  Thing  &   Other  )     {   /*обработка столкновения космического корабля с астероидом*/  } 
     void   spaceship_collision  (  Thing  &   Other  )    {   /*обработка столкновения космического корабля с космическим кораблем*/  } 

   public  : 
     Spaceship  ()  :   Thing  (  cid  )   {} 
     ​​static   void   initCases  (); 
      static   const   std  ::  uint32_t   cid  ;    // ID класса 
 }; 

  Thing  ::  CollisionHandlerMap   Thing  ::  collisionCases  ; 
  const   std  ::  uint32_t   Asteroid  ::  cid   =   typeid  (  Asteroid  ).   хэш-код  (); 
  const   std  ::  uint32_t   Космический корабль  ::  cid   =   typeid  (  Космический корабль  ).   хэш-код  (); 

  void   Asteroid::initCases  ()   { 
     addHandler  (  cid  ,   cid  ,   CollisionHandler  (  &  Asteroid  ::  asteroid_collision  )); 
      addHandler  (  cid  ,   Spaceship  ::  cid  ,   CollisionHandler  (  &  Asteroid  ::  spaceship_collision  )); 
  } 

 void   Spaceship::initCases  ()   { 
     addHandler  (  cid  ,   Asteroid  ::  cid  ,   CollisionHandler  (  &  Spaceship  ::  asteroid_collision  )); 
      addHandler  (  cid  ,   cid  ,   CollisionHandler  (  &  Spaceship  ::  spaceship_collision  )); 
  } 

 int   main  ()   { 
     Asteroid  ::  initCases  (); 
      Космический корабль  ::  initCases  (); 

      Астероид    а1  ,   а2  ; 
      Космический корабль   s1  ,   s2  ; 

      а1  .   столкнуться с  (  a2  ); 
      а1  .   столкнуться с  (  s1  ); 

      с1  .   столкнуться с  (  s2  ); 
      с1  .   столкнуться с  (  a1  ); 
  } 

YOMM2 Библиотека [21] обеспечивает быструю ортогональную реализацию открытых мультиметодов.

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

Библиотека использует комбинацию методов (сжатые таблицы диспетчеризации, целочисленные хеш-таблицы без коллизий) для реализации вызовов методов за постоянное время, одновременно уменьшая использование памяти. При использовании современного оптимизирующего компилятора диспетчеризация вызова открытого метода с одним виртуальным аргументом занимает всего на 15–30% больше времени, чем вызов обычной виртуальной функции-члена.

Пример астероидов можно реализовать следующим образом:

#include   <yorel/yomm2/keywords.hpp> 
 #include   <memory> 

 class   Thing   { 
   public  : 
     virtual   ~  Thing  ()   {} 
 }; 

  класс   Астероид   :   общественная   вещь   { 
 }; 

  класс   Космический корабль   :   общественная   вещь   { 
 }; 

  Register_classes  (  Вещь  ,   Космический корабль  ,   Астероид  ); 

  Declare_method  (  void  ,   collideWith  ,   (  virtual_  <  Thing  &>  ,   virtual_  <  Thing  &>  )); 

  define_method  (  void  ,   collideWith  ,   (  Thing  &   left  ,   Thing  &   right  ))   { 
     // обработка столкновений по умолчанию 
 } 

 define_method  (  void  ,   collideWith  ,   (  Asteroid  &   left  ,   Asteroid  &   right  ))   { 
     // обрабатываем столкновение астероид-астероид 
 } 

 define_method  (  void  ,   collideWith  ,   (  Asteroid  &   left  ,   Spaceship  &   right  ))   { 
     // обрабатываем столкновение астероида и космического корабля 
 } 

 define_method  (  void  ,   collideWith  ,   (  Spaceship  &   left  ,   Asteroid  &   right  ))   { 
     // обрабатываем столкновение космического корабля и астероида 
 } 

 define_method  (  void  ,   collideWith  ,   (  Космический корабль  &   left  ,   Космический корабль  &   вправо  ))   { 
     // обрабатываем столкновение космического корабля с космическим кораблем 
 } 

 int   main  ()   { 
     yorel  ::  yomm2  ::  update_methods  (); 

      std  ::  unique_ptr  <  Thing  >   a1  (  std  ::  make_unique  <  Asteroid  >  ()), 
         a2  (  std  ::  make_unique  <  Asteroid  >  ()); 
      std  ::  unique_ptr  <  Thing  >   s1  (  std  ::  make_unique  <  Космический корабль  >  ()), 
         s2  (  std  ::  make_unique  <  Космический корабль  >  ()); 
      // примечание: типы частично стерты 

    столкновение с  (  *  a1  ,   *  a2  );    // Столкновение астероидов с астероидами 
     CollideWith  (  *  a1  ,   *  s1  );    // Столкновение астероида и космического корабля 
     CollideWith  (  *  s1  ,   *  a1  );    // Столкновение космического корабля с астероидом 
     CollideWith  (  *  s1  ,   *  s2  );   столкновения космического корабля с космическим кораблем 

      // Возврат   0  ; 
  } 

Страуструп упоминает в книге «Дизайн и эволюция C++» , что ему понравилась концепция мультиметодов, и он рассматривал возможность реализации ее на C++, но утверждает, что не смог найти эффективный образец реализации (сравнимый с виртуальными функциями) и решить некоторые возможные проблемы неоднозначности типов. Затем он заявляет, что, хотя эту функцию все равно было бы неплохо иметь, ее можно приблизительно реализовать с использованием двойной диспетчеризации или таблицы поиска на основе типов, как показано в примере C/C++ выше, поэтому это функция с низким приоритетом для будущих версий языка. [22]

Д [ править ]

По состоянию на 2021 год Как и многие другие объектно-ориентированные языки программирования, D изначально поддерживает только одиночную диспетчеризацию. Однако в D можно эмулировать открытые мультиметоды как библиотечные функции. openmethods Библиотека [23] это пример.

// Объявление 
 матрицы   плюс  (  виртуальная  !  Матрица  ,   виртуальная  !  Матрица  ); 

  // Переопределение для двух объектов DenseMatrix 
 @method 
 Matrix   _plus  (  DenseMatrix   a  ,   DenseMatrix   b  ) 
 { 
   const   int   nr   =   a  .   ряды  ; 
    const   int   nc   =   а  .   столбцы  ; 
    утверждать  (  a  .  nr   ==   b  .  nr  ); 
    утверждать  (  a  .  nc   ==   b  .  nc  ); 
    автоматический   результат   =   новый   DenseMatrix  ; 
    результат  .   номер   =   номер  ; 
    результат  .   NC   =   NC  ; 
    результат  .   элементы  .   длина   =   а  .   элементы  .   длина  ; 
    результат  .   элементы  []   =   а  .   элементы  []   +   б  .   элементы  []; 
    вернуть   результат  ; 
  } 

 // Переопределение для двух объектов DiagonalMatrix 
 @method 
 Matrix   _plus  (  DiagonalMatrix   a  ,   DiagonalMatrix   b  ) 
 { 
   Assert  (  a  .  rows   ==   b  .  rows  ); 
    двойная  []   сумма  ; 
    сумма  .   длина   =   а  .   элементы  .   длина  ; 
    сумма  []   =   а  .   элементы  []   +   б  .   элементы  []; 
    вернуть   новую   диагональную матрицу  (  сумма  ); 
  } 

Ява [ править ]

В языке только с одной диспетчеризацией, таком как Java , множественная диспетчеризация может быть эмулирована с помощью нескольких уровней одиночной диспетчеризации:

UML-класс Java, одиночная диспетчеризация.svg

интерфейс   Collideable   { 
     voidcollideWith   (  final   Collideableother   )  ; 

      /* Этим методам потребуются разные имена на языке без перегрузки методов.   */ 
     voidcollideWith   астероида  (  последний   астероид   )  ; 
      void   CollideWith  (  последний   космический   корабль  ); 
  } 

 Класс   Asteroid   реализует   Collideable   { 
     public   voidcollideWith   //  (  final   Collideableother   )  {   Вызов 
         CollideWith для другого объекта. 
          другой  .   столкнуться с  (  это  ); 
     } 

     public   voidcollideWith   (  .  final   Asteroid   asteroid  )   { 
         // Обработка столкновения астероидов с астероидами 
      } 

     public   voidcollideWith   (  .  final   Spaceship   spaceship  )   { 
         // Обрабатываем столкновение астероида и космического корабля 
      } 
 } 

 Класс   Spaceship   реализует   Collideable   { 
     public   void   CollideWith  (  Final   Collideable   Other  )   { 
         // Вызов CollideWith для другого объекта. 
          другой  .   столкнуться с  (  это  ); 
      } 

     public   voidcollideWith   (  .  final   Asteroid   asteroid  )   { 
         // Обработка столкновения космического корабля с астероидом 
      } 

     public   voidcollideWith   (  .  final   Spaceship   spaceship  )   { 
         // Обрабатываем столкновение космического корабля с космическим кораблем 
      } 
 } 

Время выполнения instanceof Также можно использовать проверки на одном или обоих уровнях.

Поддержка языков программирования [ править ]

Первичная парадигма [ править ]

Поддержка общих мультиметодов [ править ]

Через расширения [ править ]

См. также [ править ]

Ссылки [ править ]

  1. ^ Ранка, Санджай; Банерджи, Арунава; Бисвас, Канад Кишор; Дуа, Сумит; Мишра, Прабхат; Муна, Раджат (26 июля 2010 г.). Современные вычисления: Вторая международная конференция, IC3 2010, Нойда, Индия, 9–11 августа 2010 г. Труды . Спрингер. ISBN  9783642148248 .
  2. ^ Перейти обратно: а б с д Это ж г час я дж к Мушевичи, Раду; Потанин, Алексей; Темперо, Юэн; Ноубл, Джеймс (2008). «Множественная рассылка на практике». Материалы 23-й конференции ACM SIGPLAN по языкам и приложениям объектно-ориентированных систем программирования . УПСЛА '08. Нэшвилл, Теннесси, США: ACM. стр. 563–582. дои : 10.1145/1449764.1449808 . ISBN  9781605582153 . S2CID   7605233 .
  3. ^ Перейти обратно: а б с д Это Безансон, Джефф; Эдельман, Алан; Карпински, Стефан; Шах, Вирал Б. (7 февраля 2017 г.). «Юлия: Свежий подход к численным вычислениям». Обзор СИАМ . 59 (1): 65–98. arXiv : 1411.1607 . дои : 10.1137/141000671 . S2CID   13026838 .
  4. ^ Кастанья, Джузеппе; Гелли, Джорджио и Лонго, Джузеппе (1995). «Исчисление перегруженных функций с подтипированием» . Информация и вычисления . 117 (1): 115–135. дои : 10.1006/inco.1995.1033 .
  5. ^ Кастанья, Джузеппе (1996). Объектно-ориентированное программирование: единая основа . Прогресс в теоретической информатике. Биркхойзер. п. 384. ИСБН  978-0-8176-3905-1 .
  6. ^ Кастанья, Джузеппе (1995). «Ковариантность и контравариантность: конфликт без причины». Транзакции ACM в языках и системах программирования . 17 (3): 431–447. CiteSeerX   10.1.1.115.5992 . дои : 10.1145/203095.203096 . S2CID   15402223 .
  7. ^ Брюс, Ким; Карделли, Лука; Кастанья, Джузеппе; Ливенс, Гэри Т.; Пирс, Бенджамин (1995). «О бинарных методах» . Теория и практика объектных систем . 1 (3): 221–242. дои : 10.1002/j.1096-9942.1995.tb00019.x . Проверено 19 апреля 2013 г.
  8. ^ «Использование динамического типа (Руководство по программированию на C#)» . Проверено 14 мая 2020 г.
  9. ^ "Базовые концепты" . Проверено 14 мая 2020 г.
  10. ^ «Dynamic .NET — понимание динамического ключевого слова в C# 4» . Проверено 14 мая 2020 г.
  11. ^ Groovy — Мультиметоды
  12. ^ @arrows/multimethod Множественная диспетчеризация в JavaScript/TypeScript с настраиваемым разрешением диспетчеризации, автор Maciej Cąderek.
  13. ^ Коуди, Арик, мультиметод: диспетчеризация нескольких аргументов. , получено 28 января 2021 г.
  14. ^ multimethods.py. Архивировано 9 марта 2005 г. в Wayback Machine . Множественная диспетчеризация в Python с настраиваемым разрешением диспетчеризации, Дэвид Мерц и др.
  15. ^ «Мультиметоды за пять минут на Python» .
  16. ^ «ПИК-Правила 0.5a1.dev» . Индекс пакетов Python . Проверено 21 марта 2014 г.
  17. ^ «Пи-протоколы» . Комплект корпоративных приложений Python . Проверено 26 апреля 2019 г.
  18. ^ «Рег» . Прочтите документы . Проверено 26 апреля 2019 г.
  19. ^ «Объектная система C: структура, которая выводит C на уровень других языков программирования высокого уровня и выше: CObjectSystem/COS» . Гитхаб . 2019-02-19.
  20. ^ «Отчет о языковой поддержке Multi-Methods и Open-Methods для C++» (PDF) . 11 марта 2007 г. Множественная диспетчеризация — выбор вызываемой функции на основе динамического типа двух или более аргументов — является решением нескольких классических проблем объектно-ориентированного программирования.
  21. ^ yomm2 , Быстрые ортогональные открытые мультиметоды для C++, Жан-Луи Леруа.
  22. ^ Страуструп, Бьярн (1994). «Раздел 13.8». Проектирование и эволюция C++ . Индианаполис, Индиана, США: Эддисон Уэсли. Бибкод : 1994декабрь..книга.....S . ISBN  978-0-201-54330-8 .
  23. ^ openmethods , Открытые мультиметоды для D Жана-Луи Лероя.
  24. ^ «Методы» . Руководство Юлии . Джулиаланг. Архивировано из оригинала 17 июля 2016 года . Проверено 11 мая 2014 г.
  25. ^ «Мультиметоды в C# 4.0 с динамическим интерфейсом » . Проверено 20 августа 2009 г.
  26. ^ «Язык Сесила» . Проверено 13 апреля 2008 г.
  27. ^ «Мультиметоды в Clojure» . Проверено 4 сентября 2008 г.
  28. ^ Стил, Гай Л. (1990). «28» . Общий LISP: язык . Бедфорд, Массачусетс, США: Digital Press. ISBN  978-1-55558-041-4 .
  29. ^ «Предыстория и цели» . Проверено 13 апреля 2008 г.
  30. ^ «Спецификация языка Fortress, версия 1.0» (PDF) . Архивировано из оригинала (PDF) 20 января 2013 г. Проверено 23 апреля 2010 г.
  31. ^ «Мультиметоды в Groovy» . Проверено 13 апреля 2008 г.
  32. ^ «Методы – ЛассоГид 9.2» . Проверено 11 ноября 2014 г.
  33. ^ «Шаблон посетителя и мультиметоды» . Проверено 13 апреля 2008 г.
  34. ^ «Руководство Нима: Мультиметоды» . Проверено 3 мая 2022 г.
  35. ^ «Часто задаваемые вопросы по Perl 6» . Проверено 13 апреля 2008 г.
  36. ^ «Как работают методы S4» (PDF) . Проверено 13 апреля 2008 г.
  37. ^ «Множественная отправка в Seed7» . Проверено 23 апреля 2011 г.
  38. ^ «Системное руководство TADS 3» . Проверено 19 марта 2012 г.
  39. ^ «Множественная рассылка VB.Net» . Проверено 31 марта 2020 г.
  40. ^ «Новые возможности C# 4.0 и VB.Net 10.0» . 4 ноября 2010 г. Проверено 31 марта 2020 г.
  41. ^ «Заметки для знатоков языков программирования» . Проверено 21 августа 2016 г.
  42. ^ «Множественная отправка» .

Внешние ссылки [ править ]