stringtranslate.com

Полиморфизм (информатика)

В теории языков программирования и теории типов полиморфизм это использование одного символа для представления нескольких различных типов. [1]

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

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

История

Интерес к полиморфным системам типов значительно возрос в 1990-х годах, и практические реализации начали появляться к концу десятилетия. Полиморфизм ad hoc и параметрический полиморфизм были первоначально описаны в работе Кристофера Стрейчи « Основные концепции языков программирования » [5] , где они перечислены как «два основных класса» полиморфизма. Полиморфизм ad hoc был особенностью ALGOL 68 , в то время как параметрический полиморфизм был основной особенностью системы типов ML .

В статье 1985 года Питер Вегнер и Лука Карделли ввели термин «полиморфизм включения» для моделирования подтипов и наследования , [1] ссылаясь на Simula как на первый язык программирования, реализовавший его.

Формы

Полиморфизм ad hoc

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

class  AdHocPolymorphic { public String add ( int x , int y ) { return "Сумма: " + ( x + y ); }            public String add ( String name ) { return "Добавлено " + name ; } }       public class adhoc { public static void main ( String [] args ) { AdHocPolymorphic poly = new AdHocPolymorphic ();               System.out.println ( poly.add ( 1,2 ) ); // выводит " Сумма : 3 " System.out.println ( poly.add ( " Джей " ) ) ; // выводит " Добавлен Джей " } }        

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

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

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

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

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

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

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

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

класс List < T > { класс Node < T > { T elem ; Node < T > next ; } Node < T > head ; int length () { ... } }                 Список <B> map ( Func <A , B > f , Список <A > xs ) { ... }       

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

Подтипирование

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

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

абстрактный класс Pet { абстрактный String speak (); }      класс  Cat расширяет Pet { String speak () { return "Мяу!" ; } }         класс  Собака расширяет Домашнее животное { String speak () { return "Гав!" ; } }         static void letsHear ( final Pet pet ) { println ( pet . speak ()); }      static void main ( String [] args ) { letsHear ( new Cat ()); letsHear ( new Dog ()); }        

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

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

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

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

Полиморфизм строк

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

Политипизм

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

Ранговый полиморфизм

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

Аспекты реализации

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

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

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

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

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

Смотрите также

Ссылки

  1. ^ abc Cardelli, Luca ; Wegner, Peter (декабрь 1985 г.). «О понимании типов, абстракции данных и полиморфизма» (PDF) . ACM Computing Surveys . 17 (4): 471–523. CiteSeerX  10.1.1.117.695 . doi :10.1145/6041.6042. S2CID  2921816.: «Полиморфные типы — это типы, операции которых применимы к значениям более чем одного типа».
  2. ^ Бьярне Страуструп (19 февраля 2007 г.). «Словарь терминов C++ Бьярне Страуструпа». полиморфизм — предоставление единого интерфейса для сущностей разных типов.
  3. ^ "Полиморфизм". Учебники Java™: Изучение языка Java: Интерфейсы и наследование . Oracle . Получено 2021-09-08 .
  4. ^ Коналлен, Дж.; Энгл, М.; Хьюстон, К.; Максимчук, Р.; Янг, Б.; Буч, Г. (2007). Объектно-ориентированный анализ и проектирование с приложениями (3-е изд.). Pearson Education. ISBN 9780132797443.
  5. ^ ab Strachey, Christopher (2000). «Основные концепции языков программирования». Вычисления высшего порядка и символьные вычисления . 13 (1/2): 11–49. CiteSeerX 10.1.1.332.3161 . doi :10.1023/A:1010000313106. ISSN  1573-0557. S2CID  14124601. 
  6. ^ Такер, Аллен Б. (2004). Computer Science Handbook (2-е изд.). Тейлор и Фрэнсис. стр. 91–. ISBN 978-1-58488-360-9.
  7. ^ Пирс, BC (2002). "23.2 Разновидности полиморфизма". Типы и языки программирования . MIT Press. стр. 340–1. ISBN 9780262162098.
  8. ^ Ванд, Митчелл (июнь 1989). «Вывод типа для конкатенации записей и множественного наследования». Труды. Четвертый ежегодный симпозиум по логике в компьютерных науках . стр. 92–97. doi :10.1109/LICS.1989.39162.
  9. ^ Лэммель, Ральф; Виссер, Йост (2002). «Типизированные комбинаторы для обобщенного обхода». Практические аспекты декларативных языков: 4-й международный симпозиум . Springer. стр. 137–154, см. стр. 153. CiteSeerX 10.1.1.18.5727 . ISBN  354043092X.
  10. ^ Слепак, Джастин; Шиверс, Олин; Манолиос, Панайотис (2019). «Семантика рангового полиморфизма». arXiv : 1907.00509 [cs.PL].
  11. ^ Бингесснер, Алексис. «Как Swift добился динамического связывания там, где Rust не смог».

Внешние ссылки