Открыть главное меню

Изменения

коррективы, дополнение, оформление
Параметрический полиморфизм подразумевает исполнение '''одного и того же''' кода для всех допустимых типов аргументов, тогда как {{nobr|ad hoc}} полиморфизм подразумевает исполнение потенциально '''разного''' кода для каждого типа или подтипа аргумента.
 
Определение полиморфизма как «''один интерфейс  — много реализаций''», популяризованное [[Страуструп, Бьёрн|Бьерном Страуструпом]]<ref>{{cite web
| автор = [[Страуструп, Бьёрн|Bjarne Stroustrup]].
| title = C++ Glossary
}}</ref> статическую неполиморфную типизацию (потомки [[Алгол]]а и [[BCPL]]), динамическую типизацию (потомки [[Lisp]], [[Smalltalk]], [[APL (язык программирования)|APL]]) и статическую [[полиморфизм типов|полиморфную типизацию]] (потомки [[ML]]). Использование {{nobr|ad hoc}} полиморфизма наиболее характерно для неполиморфной типизации. Параметрический полиморфизм и динамическая типизация намного существеннее, чем {{nobr|ad hoc}} полиморфизм, повышают коэффициент [[повторное использование кода|повторного использования кода]], поскольку определенная единственный раз функция реализует без дублирования заданное поведение для бесконечного множества вновь определяемых типов, удовлетворяющих требуемым в функции условиям. С другой стороны, временами возникает необходимость обеспечить различное поведение функции в зависимости от типа параметра, и тогда необходимым оказывается специальный полиморфизм.
 
[[Параметрический полиморфизм]]{{переход|#параметрический полиморфизм|text}} является синонимом '''абстракции типа'''{{sfn|Harper - Practical Foundations for Programming Languages|loc=20.1 System F|с=172}}. Он повсеместно используется в [[функциональное программирование|функциональном программировании]], где он обычно обозначается просто как «полиморфизм».
 
В сообществе [[объектно-ориентированное программирование|объектно-ориентированного программирования]] под термином «полиморфизм» обычно подразумевают [[наследование (программирование)|наследование]], а использование параметрического полиморфизма называют [[обобщённое программирование|обобщённым программированием]]{{sfn|Пирс - Типы в языках программирования|loc=23.2 Разновидности полиморфизма|с=365}}, или иногда «статическим полиморфизмом».
* 2) специальный, устроенный конкретно для данной цели или данного случая
 
Двойственность содержания термина {{nobr|«''ad hoc полиморфизм''»}} долгие годы была заслуженной{{sfn|Wadler - How to make ad-hoc polymorphism less ad hoc|с=1-2}}. Стрэчи выбрал этот термин, руководствуясь первым значением  — в работе он подчеркивает, что при {{nobr|ad hoc}} полиморфизме нет единого систематичного способа вывести тип результата из типа аргументов, и хотя возможно построение определённого набора правил для сужения спектра его поиска, но эти правила по своей природе являются спонтанными как по содержанию, так и по контексту применения{{sfn|Strachey - Fundamental Concepts|1967}}.
 
Действительно, [[ad hoc полиморфизм]] не является ''истинным'' полиморфизмом{{sfn|Cardelli - On Understanding Types|loc=1.3. Kinds of Polymorphism|с=6}}. [[Перегрузка функций]] даёт не «'''''значение''', имеющее множество типов''», а «'''''символ''', имеющий множество типов''», но значения, [[Идентификатор|идентифицируемые]] этим символом, имеют ''разные'' (потенциально {{nobr|не совместимые}}) типы. Аналогично, [[приведение типов]] не является истинным полиморфизмом: кажется, будто оператор принимает значения множества типов, но значения должны быть ''преобразованы'' к некоторому представлению до того, как он сможет их использовать, так что на самом деле оператор работает лишь над одним типом (то есть имеет один тип). Более того, [[тип возвращаемого значения]] здесь не зависит от [[Параметр (программирование)|типа входного параметра]], как в случае параметрического полиморфизма.
 
=== {{якорь|Специальный полиморфизм}} Ad hoc полиморфизм ===
{{main|:en:Ad hoc polymorphism|l1=Ad hoc polymorphismполиморфизм (англ.{{ref-en}})}}
 
[[Ad hoc]] полиморфизм (в русской литературе чаще всего переводится как «{{lang-ru2|специальный полиморфизм}}» или «{{lang-ru2|специализированный полиморфизм}}», хотя оба варианта не всегда верны{{переход|#Классификация|text}}) поддерживается во многих языках посредством [[перегрузка функций|перегрузки функций и методов]], а в [[Сильная и слабая типизация|слабо типизированных]]  — также посредством [[Приведение типов|приведения типов]].
 
В следующем примере (язык [[Pascal]]) функции <code>Add</code> выглядят как реализующие одну и ту же функциональность над разными типами, но компилятор определяет их как две совершенно разные функции.
Параметрический полиморфизм позволяет определять функцию или тип данных обобщённо, так что значения обрабатываются идентично вне зависимости от их типа. Параметрически полиморфная функция использует аргументы на основе поведения, а не значения, апеллируя лишь к необходимым ей свойствам аргументов, что делает её применимой в любом контексте, где тип объекта удовлетворяет заданным требованиям поведения. Таким образом, реализуется концепция {{iw|Параметричность|параметричности|en|parametricity}}{{sfn|Пирс - Типы в языках программирования|loc=23.9 Параметричность|с=384-385}}.
 
Развитые [[система типов|системы типов]] (такие как [[Система типов Хиндли — Милнера|Хиндли  — Милнер]]) предоставляют механизмы для определения [[полиморфизм типов|полиморфных типов]], что делает использование полиморфных функций более удобным и обеспечивает статическую [[типобезопасность]]. Такие системы являются системами типов второго порядка, добавляющими к системам типов первого порядка (используемым в большинстве [[процедурное программирование|процедурных языков]]) параметризацию типов (посредством [[переменная типа|ти́повой переменной]]) и [[абстрактный тип данных|абстракцию типов]] (посредством [[переменная типа#Связывание и квантификация переменных типа|экзистенциальной квантификации]] над ними). В системах типов второго порядка нет непосредственной необходимости в поддержке [[примитивный тип|примитивных типов]], так как они могут быть выражены посредством более развитых средств.{{sfn|Cardelli - Type systems|loc=5 Second-order Type Systems|с=25}}
 
Классическим примером полиморфного типа служит ''[[список (программирование)|список]] элементов произвольного типа'', для которого во многих языках, типизируемых по [[Система типов Хиндли — Милнера|Хиндли  — Милнеру]] (большинство [[Статическая типизация|статически типизируемых]] [[функциональное программирование|функциональных языков программирования]]), предоставляется [[синтаксический сахар]]. Следующий пример демонстрирует определение нового [[Алгебраический тип данных|алгебраического типа]] «параметрически полиморфный [[список (программирование)|список]]» и двух функций над ним:
<source lang=haskell>
data List a = Nil | Cons a (List a)
map f (Cons x xs) = Cons (f x) (map f xs)
</source>
При подстановке в [[переменная типа|ти́повую переменную]] <code>a</code> конкретных типов <code>Int</code>, <code>String</code> и  т.  д. будут построены, соответственно, конкретные типы <code>List Int</code>, <code>List String</code> и  т.  д. Эти конкретные типы, в свою очередь, снова могут быть подставлены в эту [[переменная типа|ти́повую переменную]], порождая типы <code>List List String</code>, <code>List (Int, List String)</code> и  т.  д. При этом для всех объектов всех построенных типов будет использоваться ''одна и та же'' физическая реализация функций <code>length</code> и <code>map</code>.
 
Параметрический полиморфизм также доступен в некоторых [[императивный язык программирования|императивных]] (в частности, [[объектно-ориентированный язык программирования|объектно-ориентированных]]) языках программирования, где для его обозначения обычно используется термин «[[обобщённое программирование]]». В частности, в языке [[Си (язык программирования)|Си]] нетипизированный параметрический полиморфизм традиционно обеспечивается за счёт использования нетипизированного [[указатель (программирование)|указателя]] <code>void*</code>, хотя возможна и типизированная форма. Использование [[Шаблоны C++|шаблонов C++]] внешне похоже на параметрический полиморфизм, но семантически реализуется сочетанием [[ad hoc полиморфизм|ad hoc]]-механизмов; в сообществе [[С++]] его называют «''статическим полиморфизмом''» (для противопоставления «''динамическому полиморфизму''»{{переход|#Подтипизация на записях|text}}).
Поддержка рядного полиморфизма имеется в современных версиях [[OCaml]]{{sfn|Мински в переводе ДМК|loc=Подтипизация|с=259}}.
 
Рядный полиморфизм является частным случаем [[параметрический полиморфизм|параметрического полиморфизма]]{{переход|#Параметрический полиморфизм|text}}  — [[запись (тип данных)|запись]] становится истинно полиморфной  — поэтому его также называют «''полиморфизмом записей''» ({{lang-en2|record polymorphism}}), что может приводить к путанице с «''полиморфизмом подтипов на записях''»{{переход|#Подтипизация на записях|text}} ({{lang-en2|subtype polymorphism on records}}), представляющим независимую концепцию. Подтипизация в полиморфном языке существенно усложняет систему типов{{sfn|Пирс - Типы в языках программирования|loc=16. Метатеория подтипов|с=225}}; рядный полиморфизм проще в реализации, и при отсутствии подтипизации предоставляет достаточную выразительность для применения [[объектно-ориентированное проектирование|объектно-ориентированного проектирования]], хотя и с большей трудоёмкостью ([[OCaml]] поддерживает обе возможности).
 
'''''Замечание'''  — {{iw|Митчел Уэнд||en|Mitchell Wand}}, считающийся автором рядного полиморфизма{{sfn|Wand - type inference for objects}}, заимствовал термин «row» ({{lang-ru|ряд, цепочка, строка}}) из [[Алгол-68|Алгола-68]], где он означал множество представлений. В контексте Алгола в русскоязычной литературе этот термин традиционно переводился как «мультивид». Встречается также вариант перевода «row variables» как «строчные переменные»{{sfn|Пирс - Типы в языках программирования|loc=1.4 Краткая история|с=11-13}}, вызывающий путаницу со [[строчная буква|строчными буквами]] в [[строковый тип|строковых типах]].''
 
==== Полиморфная рекурсия ====
{{main|:en:Polymorphic recursion|l1=Полиморфная рекурсия ({{ref-en}})}}
 
Традиционно в [[полиморфизм типов|полиморфно типизированных]] языках (потомках [[ML]]{{переход|#Общие сведения|text}}) функция может быть полиморфной только при взгляде «извне» (т.е.то есть её можно применять к аргументам различных типов), но её определение может содержать только мономорфную [[рекурсия|рекурсию]] (т.е.то есть разрешение типов осуществляется до вызова). В расширении [[Система типов Хиндли — Милнера|Хиндли  — Милнера]], известном как исчисление Милнера  — Майкрофта, формализуется определение функций над ''рекурсивно определенными термами'' (т.е.то есть [[алгебраический тип данных|алгебраическими типами]], [[конструктор (функциональное программирование)|конструкторы]] которых могут параметризоваться [[Параметрический полиморфизм#Импредикативный полиморфизм|импредикативно]]). [[Выведение типов]] для этого исчисления [[алгоритмическая разрешимость|неразрешимо]].{{sfn|Пирс - Типы в языках программирования|loc=Глава 22. Реконструкция типов. Раздел 22.8. Дополнительные замечания|с=362}}
 
=== Полиморфизм подтипов ===
{{main|:en:Subtyping|l1=Выделение подтипов данных ({{ref-en}})}}
 
'''Полиморфизм включения''' ({{lang-en2|inclusion polymorphism}}) является обобщённой формализацией {{iw|выделение подтипов данных|подтипизации|en|Subtyping}} и [[наследование (программирование)|наследования]]{{sfn|Cardelli - On Understanding Types|}}. Эти понятия не следует путать: {{iw|выделение подтипов данных|подтипы|en|Subtyping}} определяют отношения на уровне интерфейсов, тогда как наследование определяет отношения на уровне реализации{{sfn|Mitchell - Concepts in Programming Languages|loc=10.2.6 Inheritance Is Not Subtyping|с=287}}.
 
Подтипизация ({{lang-en2|subtyping}}), или полиморфизм подтипов ({{lang-en2|subtype polymorphism}}), означает, что поведение [[параметрический полиморфизм|параметрически полиморфной]]{{переход|#параметрический полиморфизм|text}} функции ограничивается множеством типов, ограниченных в иерархию «супертип  — подтип»{{sfn|Cardelli - Typeful programming|}}{{sfn|Cardelli - On Understanding Types|}}{{sfn|Пирс - Типы в языках программирования|loc=15 Подтипы|с=193}}. Например, если имеются типы <code>Number</code>, <code>Rational</code> и <code>Integer</code>, ограниченные отношениями <code>Number :> Rational</code> и <code>Number :> Integer</code>, то функция, определённая на типе <code>Number</code>, также сможет принять на вход аргументы типов <code>Integer</code> или <code>Rational</code>, и её поведение будет идентичным. Действительный тип объекта может быть скрыт как «чёрный ящик», и предоставляться лишь по запросу идентификации объекта. На самом деле, если тип <code>Number</code> является абстрактным, то конкретного объекта этого типа даже не может существовать (см. [[абстрактный класс]], но не следует путать с [[абстрактный тип данных|абстрактным типом данных]]). Данная иерархия типов известна (особенно в контексте языка [[Scheme (язык программирования)|Scheme]]) как {{iw|числовая башня||en|Numerical tower}}, и обычно содержит большее количество типов.
 
Идея подтипов мотивируется увеличением множества типов, которые могут обрабатываться уже написанными функциями, и за счёт этого повышением коэффициента [[повторное использование кода|повторного использования кода]] в условиях [[сильная и слабая типизация|сильной типизации]] (то есть увеличением множества [[типобезопасность|типизируемых]] программ). Это обеспечивается '''правилом включения''' ({{lang-en2|subsumption rule}}): «''если выражение <code>e</code> принадлежит к типу <code>t'</code> в контексте типизации <code>Г</code>, и выполняется <code>t'<:t</code>, то <code>e</code> принадлежит также и к типу <code>t</code>''»{{sfn|Пирс - Типы в языках программирования|loc=15. Подтипы|с=193}}{{sfn|Harper - Practical Foundations for Programming Languages|loc=23.1. Subsumption|с=208}}.
==== Подтипизация на записях ====
 
Подтипизация на [[запись (тип данных)|записях]] (не путать с полиморфизмом записей{{переход|#Рядный полиморфизм|text}}), также известная как ''включение'' или ''вхождение'' ({{lang-en2|'''subsumption'''}}  — см. [[принцип подстановки Барбары Лисков]]), является теоретическим обоснованием [[объектно-ориентированное программирование|объектно-ориентированного программирования (ООП)]]{{sfn|Abadi, Cardelli - Semantics of Object Types}}{{sfn|Cardelli - On Understanding Types|loc=6. Bounded Quantification|с=28}}{{sfn|Пирс - Типы в языках программирования|loc=15 Подтипы|с=193}}{{sfn|Мински в переводе ДМК|loc=Подтипизация|с=259}}. Формально её отношения с [[параметрический полиморфизм|параметрическим полиморфизмом]] описываются {{iw|ограниченная квантификация|ограниченной квантификацией|en|bounded quantification}} и [[Ковариантность и контравариантность (программирование)|ковариантностью/контравариантностью]] (или полярностью) [[Конструктор типов|конструкторов типов]]{{sfn|Cardelli - On Understanding Types|loc=6. Bounded Quantification|с=28}}. Проще говоря, супертипы в ООП представляют собой [[полиморфизм типов|параметрические типы]], [[переменная типа|параметр которых]] задаётся неявно{{sfn|Cardelli - On Understanding Types|с=9}}.
 
В подтипизации на [[запись (тип данных)|записях]] выделяются две разновидности: в ширину и в глубину.
===== Методы в подтипах записей =====
 
Полноценная поддержка [[объектно-ориентированное программирование|объектно-ориентированного программирования]] предполагает включение в число полей [[запись (тип данных)|записей]] также [[функция (программирование)|функций]], обрабатывающих значения типов записей, которым они принадлежат{{sfn|Abadi, Cardelli - Semantics of Object Types}}{{sfn|Cardelli - On Understanding Types|loc=2.3. Basic Types, Structured Types and Recursion|с=12-14}}. Такие функции традиционно называются «'''[[метод (программирование)|методами]]'''». Обобщённой моделью связывания записей с методами является матрица диспетчеризации ({{lang-en2|dispatch matrix}}); на практике большинство языков раскладывают её на вектора по строкам либо по столбцам  — соответственно, реализуя либо организацию на основе классов ({{lang-en2|class-based organisation}}), либо организацию на основе методов ({{lang-en2|method-based organisation}}){{sfn|Harper - Practical Foundations for Programming Languages|loc=Chapter 25. Dynamic Dispatch|с=229}}. При этом следует отличать ''переопределение методов в подтипах'' ({{lang-en2|method overriding}}) от ''подтипизации функций'' ({{lang-en2|functional subtyping}}). Переопределение методов не связывает их отношениями подтипизации на функциях, но позволяет изменять сигнатуры их типов. При этом возможны три варианта: инвариантное, ковариантное и контравариантное переопределение, и два последних используют подтипизацию своих параметров, или (реже) [[приведение типов]]{{sfn|Joyner|1996|loc=3.38 Signature Variance|с=35}} (подробнее см. [[Ковариантность и контравариантность (программирование)|ковариантность и контравариантность]]).
 
Многие [[объектно-ориентированное программирование|объектно-ориентированные языки]] предусматривают встроенный механизм связывания [[функция (программирование)|функций]] в [[метод (программирование)|методы]], реализуя таким образом организацию программ на основе классов. Языки, рассматривающие функции как [[объект первого класса|объекты первого класса]] и [[система типов|типизирующие]] их (см. [[функции первого класса]], [[функциональный тип]]  — не путать с [[тип возвращаемого значения|типом возвращаемого значения функции]]), позволяют произвольно выстраивать организацию на основе методов, что обеспечивает возможность производить [[объектно-ориентированное проектирование]] без прямой поддержки со стороны языка<ref name="MLton_OOP">[http://www.mlton.org/ObjectOrientedProgramming Object-Oriented Programming in Standard ML]</ref>. Некоторые языки (например, [[OCaml]]) поддерживают обе возможности.
 
Языки с [[система типов|системами типов]], основанными на формальной теории подтипизации ([[OCaml]], проект {{nobr|[[successor ML]]}}), рассматривают системы [[объект (программирование)|объектов]] и системы [[класс (программирование)|классов]] независимо{{sfn|Мински в переводе ДМК|loc=Глава 11. Объекты|с=253}}<ref name=ML2000>{{статья
}}</ref>. Это значит, что с объектом связывается прежде всего ''объектный тип'', и лишь при явном указании объектный тип связывается с неким классом. При этом {{iw|динамическая диспетчеризация||en|Dynamic dispatch}} осуществляется на уровне объекта, а значит, в таких языках два объекта, относящиеся к одному классу, вообще говоря, могут иметь различный набор методов. Вместе с формально определённой семантикой [[множественное наследование|множественного наследования]] это даёт непосредственную всестороннюю поддержку [[Примесь (программирование)|примесей]].
 
[[CLOS]] используетреализует организациюматрицу надиспетчеризации основе методов. При этом используется формализованная модельпосредством [[мультиметод]]ов, то есть {{iw|динамическая диспетчеризация|динамически диспетчеризуемых|en|Dynamic dispatching}} методов, полиморфных сразу по нескольким аргументам<ref>{{статья
| автор = Castagna, Ghelli, Longo.
| заглавие = A calculus for overloaded functions with subtyping.
}}</ref>.
 
Некоторые языки, напротив, используют своебразные [[ad hoc]]-решения. Например, [[система типов]] языка [[С++]] предусматривает автоматическое [[приведение типов]] (то есть является [[сильная и слабая типизация|слабой]]), {{nobr|не [[полиморфизм типов|полиморфная]]}}, не поддерживает {{iw|Выделение подтипов данных|выделение подтипов|en|Subtyping}} и абстракцию типов (не путать с [[Сокрытие (программирование)|сокрытием]] полей) и определяет [[Ковариантность и контравариантность (программирование)|инвариантность]] сигнатур методов. [[наследование (программирование)|Наследование]] в [[С++]] реализуется набором {{nobr|ad hoc-механизмов}}, однако, его использование называется в сообществе языка «полиморфизмом» (а [[Сокрытие (программирование)|сокрытие]] полей  — «абстракцией»{{sfn|Joyner|1996|loc=2.8 Encapsulation|с=8}}). Использование такого языка может быть [[типобезопасность|небезопасно]] (нельзя гарантировать устойчивость программ){{sfn|Mitchel - Concepts in Programming Languages|2004|loc=6.2.1 Type Safety|с=132-133}}{{sfn|Joyner|1996|loc=3.38 Signature Variance|с=35}}. В качестве особенности можно отметить наличие в [[С++]] (неформализуемой) возможности управлять графом наследования: [[ромбовидное наследование]] в С++ называется «''виртуальным наследованием''» и задаётся явным атрибутом <code>virtual</code>; по умолчанию же осуществляется дублирование унаследованных полей с доступом к ним по квалифицированному имени.
 
==== Подтипизация высшего порядка ====
 
=== Классы типов ===
{{main|:en:Type class|l1=Классы типов ({{ref-en}})}}
 
{{iw|Класс типов||en|Type class}} реализует единую независимую таблицу виртуальных методов для множества ([[Параметрический полиморфизм|универсально]] [[переменная типа#Связывание и квантификация переменных типа|квантифицированных]]) типов. Этим классы типов отличаются от [[класс (объектно-ориентированное программирование)|классов]] в [[Объектно-ориентированное программирование|объектно-ориентированном программировании]], где всякий объект всякого ({{iw|ограниченная квантификация|ограниченно|en|Bounded quantification}} [[переменная типа#Связывание и квантификация переменных типа|квантифицированного]]) типа сопровождается указателем на таблицу виртуальных методов{{sfn|Wadler - How to make ad-hoc polymorphism less ad hoc|с=3}}. Классы типов являются не типами, но категориями типов; их инстансы представляют собой не значения, а типы.
(==) :: Eq a => a -> a -> Bool
</source>
Для снижения рутинного кодирования некоторых часто очевидно необходимых свойств пользовательских типов в [[Haskell|Хаскеле]] дополнительно предусмотрен [[синтаксический сахар]]  — конструкция <code>deriving</code>, допустимая для ограниченного набора стандартных классов типов (таких как <code>Eq</code>). (В русскоязычном сообществе её использование нередко путается с понятием «[[наследование (программирование)|наследования]]» из-за особенностей перевода слова «''derive''».)
 
=== Обобщённые алгебраические типы данных ===
 
=== Политипизм ===
{{main|:en:Generic programming#Functional languages|l1=Обобщённое программирование#Функциональные языки ({{ref-en}})}}
 
Иногда используется термин «политипизм» или «обобщённость типа данных». По сути политипизм означает встроенную в язык поддержку полиморфизма [[конструктор типов|конструкторов типов]], предназначенную для унификации программных интерфейсов и повышения [[повторное использование кода|повторного использования кода]]. Примером политипизма является обобщённый алгоритм [[сопоставление с образцом|сопоставления с образцом]]<ref>{{статья
sum :: Regular d => d Int -> Int
</source>
Первая функция (<code>head</code>) является полиморфной (параметрически полиморфной{{переход|#Параметрический полиморфизм|text}}), вторая (инфиксный оператор «<code>+</code>»)  — перегруженной ({{nobr|ad hoc}} полиморфной{{переход|#Ad hoc полиморфизм|text}}), третья и четвёртая  — политиповыми: [[переменная типа]] <code>d</code> в их определении варьируется над [[конструктор типов|конструкторами типов]]. При этом, третья функция (<code>length</code>) является ''политиповой '''и''' полиморфной'' (предположительно, она вычисляет «длину» для некоторого множества полиморфных агрегатных типов  — например, количество элементов в [[список (структура данных)|списках]] и в [[дерево (структура данных)|деревьях]]), а четвёртая (<code>sum</code>) является ''политиповой, '''но не''' полиморфной'' (мономорфной над агрегатными типами, принадлежащими {{iw|Класс типов|классу типов|en|type class}} <code>Regular</code>, для которых она, вероятно, вычисляет сумму целых, образующих объект конкретного агрегатного типа).
 
=== Прочее ===
 
[[динамическая типизация|Динамически типизируемые]] языки единообразно представляют разновидности полиморфизма, что формирует самобытную идеологию в них и влияет на применяемые методологии декомпозиции задач. Например, в [[Smalltalk]] любой класс способен принять сообщения любого типа, и либо обработать его самостоятельно (в том числе посредством [[Отражение (программирование)|интроспекции]]), либо ретранслировать другому классу  — таким образом, любой метод формально является параметрически полиморфным, при этом его внутренняя структура может [[Оператор ветвления|ветвиться]] по условию динамического типа аргумента, реализуя специальный полиморфизм. В [[CLOS]] [[мультиметод]]ы одновременно являются [[функции первого класса|функциями первого класса]], что позволяет рассматривать их одновременно и как {{iw|ограниченная квантификация|ограниченно квантифицированные|en|Bounded quantification}}, и как [[обобщённое программирование|обобщённые]] ([[параметрический полиморфизм|истинно полиморфные]]).
 
Статически [[полиморфизм типов|полиморфно типизированные]] языки, напротив, могут реализовать разновидности полиморфизма ортогонально (независимо друг от друга), позволяя выстраивать их хитросплетение [[типобезопасность|типобезопасным]] образом. Например, [[OCaml]] поддерживает [[полиморфизм типов|параметрические]] классы (по возможностям аналогичные [[Шаблоны C++|шаблонам классов C++]], но верифицируемые без необходимости инстанцирования), их [[наследование (программирование)|наследование]] вширь и вглубь{{переход|#Подтипизация на записях|text}} (в том числе [[множественное наследование|множественное]]), [[идиома (программирование)|идиоматическую]] реализацию {{iw|Класс типов|классов типов|en|type class}}{{переход|#Классы типов|text}} (посредством сигнатур  — см. соответствующий [[Язык модулей ML#Реализация альтернативных моделей|пример использования языка модулей ML]]), рядный полиморфизм{{переход|#рядный полиморфизм|text}}, [[параметрический полиморфизм#полиморфизм ранга k|параметрический полиморфизм рангов выше 1-го]] (посредством так называемых ''локально-абстрактных типов'', реализующих [[экзистенциальный тип|экзистенциальные типы]]) и [[обобщённый алгебраический тип данных|обобщённые алгебраические типы данных]]{{переход|#обобщённые алгебраические типы данных|text}}.
 
== История ==