Из Википедии, бесплатной энциклопедии
Перейти к навигации Перейти к поиску

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

Наиболее общепризнанными основными классами полиморфизма являются:

  • Специальный полиморфизм : определяет общий интерфейс для произвольного набора индивидуально определенных типов.
  • Параметрический полиморфизм : когда один или несколько типов указаны не по имени, а с помощью абстрактных символов, которые могут представлять любой тип.
  • Подтипирование (также называемое полиморфизмом подтипа или полиморфизмом включения ): когда имя обозначает экземпляры многих различных классов, связанных некоторым общим суперклассом. [3]

История [ править ]

Интерес к системам полиморфных типов значительно вырос в 1960-х, а к концу десятилетия начали появляться практические реализации. Специальная полиморфизм и параметрический полиморфизм первоначально были описаны в Christopher Стрейчи «s Основные понятия в Языки программирования , [4] , где они перечислены в качестве„двух основных классов“полиморфизма. Специальный полиморфизм был особенностью Algol 68 , в то время как параметрический полиморфизм был ключевой особенностью системы типов ML .

В 1985 году работе, Питер Вегнер и Лука Cardelli ввел термин включение полиморфизм к модели подтипов и наследования , [2] со ссылкой на Simula в качестве первого языка программирования для его реализации.

Типы [ править ]

Специальный полиморфизм [ править ]

Кристофер Стрейчи выбрал термин специальный полиморфизм для обозначения полиморфных функций, которые могут применяться к аргументам разных типов, но ведут себя по-разному в зависимости от типа аргумента, к которому они применяются (также известный как перегрузка функции или перегрузка оператора ). [5] Термин « ad hoc » в данном контексте не имеет уничижительного значения; это просто относится к тому факту, что этот тип полиморфизма не является фундаментальной особенностью системы типов. В приведенном ниже примере Pascal / DelphiAdd Функции, похоже, работают в общем над различными типами при просмотре вызовов, но компилятор считает две совершенно разные функции для всех намерений и целей:

программа  Adhoc ;функция  Add ( x ,  y  :  Integer )  :  Integer ; начало  Добавить  : =  x  +  y конец ;функция  Add ( s ,  t  :  String )  :  String ; begin  Добавить  : =  Concat ( s ,  t ) end ;начать  Writeln ( Добавить ( 1 ,  2 )) ;  (* Выводит "3" *)  Writeln ( Add ( 'Hello,' ,  'Mammals!' )) ;  (* Выводит «Здравствуйте, млекопитающие!» *) End .

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

Неявное преобразование типов также определяется как форма полиморфизма, называемая «полиморфизмом принуждения». [2] [6]

Параметрический полиморфизм [ править ]

Параметрический полиморфизм позволяет записывать функцию или тип данных в общем виде, чтобы они могли обрабатывать значения единообразно, независимо от их типа. [7] Параметрический полиморфизм - это способ сделать язык более выразительным, сохраняя при этом полную статическую типобезопасность .

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

Параметрический полиморфизм повсеместно используется в функциональном программировании, где его часто называют просто «полиморфизмом». В следующем примере в Haskell показан параметризованный тип данных списка и две параметрически полиморфные функции для них:

 список  данных a  =  Nil  |  Минусы  a  ( список  a )length  ::  List  a  ->  Целочисленная длина  Nil  =  0 length  ( Cons  x  xs )  =  1  +  length  xsmap  ::  ( a  ->  b )  ->  List  a  ->  List  b map  f  Nil  =  Nil map  f  ( Cons  x  xs )  =  Cons  ( f  x )  ( map  f  xs )

Параметрический полиморфизм также доступен в нескольких объектно-ориентированных языках. Например, шаблоны в C ++ и D или под именем generics в C #, Delphi и Java:

class  List < T >  {  class  Node < T >  {  T  elem ;  Узел < T >  следующий ;  }  Node < T >  head ;  int  length ()  {  ...  } }Список < B >  карта ( Func < , B > е , Список < > хз ) { ... }      

Джон С. Рейнольдс (а позже Жан-Ив Жирар ) формально развил это понятие полиморфизма как расширение лямбда-исчисления (названного полиморфным лямбда-исчислением или системой F ). Любая параметрически полиморфная функция обязательно ограничена в том, что она может делать, работая с формой данных, а не с их значением, что приводит к концепции параметричности .

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

Некоторые языки используют идею подтипов (также называемых полиморфизмом подтипов или полиморфизмом включения ), чтобы ограничить диапазон типов, которые могут использоваться в конкретном случае полиморфизма. В этих языках подтипирование позволяет записать функцию, которая принимает объект определенного типа T , но также работает правильно, если передан объект, принадлежащий к типу S, который является подтипом T (согласно принципу подстановки Лискова ) . Этот тип отношения иногда пишется S  <:  T . С другой стороны , Т называется быть супертипом из S-Written Т  :>  S . Полиморфизм подтипа обычно разрешается динамически (см. Ниже).

В следующем примере мы делаем кошек и собак подтипами животных. Процедура letsHear()принимает животное, но также будет работать правильно, если ей будет передан подтип:

абстрактный  класс  Animal  {  абстрактный  String  talk (); }class  Cat  расширяет  Animal  {  String  talk ()  {  return  "Meow!" ;  } }class  Dog  расширяет  Animal  {  String  talk ()  {  return  "Woof!" ;  } }static  void  letHear ( final  Animal  a )  {  println ( a . talk ()); }static  void  main ( String []  args )  {  letHear ( new  Cat ());  LetHear ( новая  собака ()); }

В другом примере, если номер , Rational , и Integer являются такими типами, что Number  :>  Rational и Number  :>  Integer , функция написано взять номер будет работать одинаково хорошо , когда прошел Integer или Rational , как , когда принята номер . Фактический тип объекта может быть скрыт от клиентов в черном ящике и доступен через идентификацию объекта . Фактически, если тип Number является абстрактным , может быть даже невозможно получить в руки объект, чейнаиболее производным типом является Number (см. абстрактный тип данных , абстрактный класс ). Этот конкретный вид иерархии типов известен - особенно в контексте языка программирования Scheme - как числовая башня и обычно содержит гораздо больше типов.

Объектно-ориентированные языки программирования предлагают полиморфизм подтипов с использованием подклассов (также известных как наследование ). В типичных реализациях каждый класс содержит то, что называется виртуальной таблицей - таблицей функций, реализующих полиморфную часть интерфейса класса, - и каждый объект содержит указатель на «vtable» своего класса, с которым затем обращаются всякий раз, когда полиморфная вызывается метод. Этот механизм является примером:

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

То же самое и с большинством других популярных объектных систем. Однако некоторые из них, такие как Common Lisp Object System , обеспечивают множественную диспетчеризацию , при которой вызовы методов полиморфны по всем аргументам.

Взаимодействие между параметрическим полиморфизмом и подтипами приводит к концепциям дисперсии и ограниченной количественной оценки .

Полиморфизм строк [ править ]

Полиморфизм строк [8] - это похожее, но отличное от подтипа понятие. Он имеет дело со структурными типами . Он позволяет использовать все значения, типы которых имеют определенные свойства, без потери оставшейся информации о типе.

Политипизм [ править ]

Связанное с этим понятие - политипизм (или универсальность типов данных ). Политипическая функция является более общей, чем полиморфная, и в такой функции, «хотя можно предоставить фиксированные специальные случаи для определенных типов данных, специальный комбинатор отсутствует». [9]

Аспекты реализации [ править ]

Статический и динамический полиморфизм [ править ]

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

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

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

Когда полиморфизм предоставляется через библиотеку , статический полиморфизм становится невозможным для динамических библиотек, поскольку нет способа узнать, какие типы параметров имеют при построении общего объекта . В то время как такие языки, как C ++ и Rust, используют мономорфизированные шаблоны, язык программирования Swift широко использует динамическую отправку для создания бинарного интерфейса приложения для этих библиотек по умолчанию. В результате можно совместно использовать больше кода для уменьшения размера системы за счет накладных расходов времени выполнения. [10]

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

  • Утиная типизация для полиморфизма без (статических) типов
  • Полиморфный код (терминология компьютерных вирусов)
  • Система F для лямбда-исчисления с параметрическим полиморфизмом.
  • Типовой класс
  • Теория типов
  • Виртуальное наследование

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

  1. ^ Бьярне Страуструп (19 февраля 2007). "Глоссарий C ++ Бьярна Страуструпа" . полиморфизм - предоставление единого интерфейса для сущностей разных типов.
  2. ^ a b c Карделли, Лука ; Вегнер, Питер (декабрь 1985 г.). «О понимании типов, абстракции данных и полиморфизме» (PDF) . ACM Computing Surveys . 17 (4): 471–523. CiteSeerX 10.1.1.117.695 . DOI : 10.1145 / 6041.6042 . ISSN 0360-0300 .   : «Полиморфные типы - это типы, операции которых применимы к значениям более чем одного типа».
  3. ^ Буч и др. 2007 Объектно-ориентированный анализ и дизайн с приложениями. Эддисон-Уэсли.
  4. Перейти ↑ Strachey, Christopher (2000). «Фундаментальные концепции языков программирования». Вычисление высшего порядка и символическое вычисление . 13 (1/2): 11–49. CiteSeerX 10.1.1.332.3161 . DOI : 10,1023 / А: 1010000313106 . ISSN 1573-0557 .  
  5. ^ Кристофер Стрейчи. Основные понятия языков программирования (PDF) . www.itu.dk . Kluwer Academic Publishers. Архивировано из оригинального (PDF) 12 августа 2017 года . Проверено 13 октября 2012 .
  6. Аллен Б. Такер (28 июня 2004 г.). Справочник по информатике, второе издание . Тейлор и Фрэнсис. С. 91–. ISBN 978-1-58488-360-9.
  7. ^ Пирс, BC 2002 Типы и языки программирования. MIT Press.
  8. Перейти ↑ Wand, Mitchell (июнь 1989 г.). «Вывод типа для объединения записей и множественного наследования». Ход работы. Четвертый ежегодный симпозиум по логике в компьютерных науках . С. 92–97. DOI : 10,1109 / LICS.1989.39162 .
  9. ^ Ральф Ламмель и Йост Виссер, "Типизированные комбинаторы для общего обхода", в Практических аспектах декларативных языков: 4-й Международный симпозиум (2002), стр. 153.
  10. ^ Beingessner, Алексис. «Как Swift добился динамического связывания там, где не смог Rust» .

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

  • Примеры полиморфизма в C ++
  • Объекты и полиморфизм (визуальный пролог)