stringtranslate.com

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

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

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

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

История

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

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

Формы

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

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

класс  AdHocPolymorphic { public String add ( int x , int y ) { return "Sum:" + ( x + y ); }            public String add ( Имя строки ) { return «Добавлено» + имя ; } }       общественный класс adhoc { public static void main ( String [] args ) { AdHocPolymorphic поли = новый AdHocPolymorphic ();               Система . вне . println ( poly.add ( 1 , 2 ) ) ; _ // печатает «Сумма: 3» System . вне . println ( poly.add ( " Джей" ) ) ; // печатает «Добавлен Джей» } }        

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

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

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

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

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

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

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

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

Список классов < T > { Узел класса < T > { T elem ; Узел <T> следующий ; _ _ } Узел <T> head ; _ _ длина int () { ... } }                 Список <B> карта ( Func < A , B > f , Список < A > xs ) { ... } _ _       

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

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

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

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

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

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

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

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

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

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

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

Политипизм

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

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

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

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

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

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

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

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

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

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

Рекомендации

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

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