Ну, дело сделано, можно теперь и про терминологию поговорить. Каким определением ad hoc полиморфизма ты пользуешься?
Я не оберонщик, поэтому не придумываю новых расшифровок для старых, давно известных терминов. Вот
program Adhoc;
function Add( x, y : Integer ) : Integer;
begin
Add := x + y
end;
function Add( s, t : String ) : String;
begin
Add := Concat( s, t )
end;
begin
Writeln(Add(1, 2));
Writeln(Add('Hello, ', 'World!'));
end.
Вообще, если обращаться к классике программирования, то всё это расписано у Луки Карделли
1.3 Виды полиморфизмаТрадиционные типизированные языки, например Паскаль, основаны на идее, что функции и процедуры, и, следовательно, их операнды имеют уникальный тип. Такие языки называются мономорфными (monomorphic), в том смысле, что каждая значение и переменная могут интерпретироваться как один и только один тип. Мономорфные языки программирования могут быть противопоставлены полиморфным (polymorphic) языкам, в которых некоторые значения и переменные могут иметь более одного типа. Полиморфные функции – это функции, чьи операнды (фактические параметры) могут иметь более одного типа. Полиморфные типы – это типы, операции над которыми применимы к значениям более чем одного типа.
Рисунок 1. Варианты полиморфизма.
Straychey [67] неформально определил два главных типа полиморфизма.
В случае параметрического полиморфизма функция одинаково работает с некоторым диапазоном типов: эти типы, как правило, имеют сходную структуру. Перегрузка (ad-hoc polymorphism) проявляется, если функция работает (или выглядит работающей) с несколькими разными типами (которые могут и не иметь общей структуры) и может вести себя различным образом в разных случаях.
Наша классификация полиморфизма (рисунок 1) развивает классификацию Strachey, вводя новую форму полиморфизма, полиморфизм включения (inclusion polymorphism), для моделирования подтипов и наследования. Параметрический полиморфизм и полиморфизм включения классифицированы как две главных подкатегории универсального полиморфизма, который противопоставлен не универсальному полиморфизму (перегрузке). Таким образом, рисунок 1, отражая точку зрения Strachey на полиморфизм, добавляет полиморфизм включения для моделирования объектно-ориентированного программирования.
Параметрический полиморфизм называется так потому, что единообразие структур типов обычно достигается с помощью параметров типов, но единообразия можно добиться разными способами, и эта более общая концепция называется универсальным полиморфизмом. Универсально полиморфные функции будут нормально работать с бесконечным количеством типов (имеющих некоторую общую структуру), а перегруженные функции будут работать только с конечным множеством разных и потенциально несвязанных типов. В случае универсального полиморфизма можно с уверенностью заявить, что некоторые значения имеют много типов, что трудно поддерживать в случае перегруженных функций, и, с некоторой точки зрения, функции перегрузки – это небольшое множество мономорфных функций. В смысле реализации универсальные полиморфные функции будут выполнять один и тот же код для аргументов всех допустимых типов, тогда как перегруженные функции могут исполнять разный код для каждого типа аргументов.
Существует два основных типа универсального полиморфизма, то есть два пути, при которых значение может иметь много типов. При параметрическом полиморфизме полиморфная функция имеет явный или неявный параметр типа, определяющий тип аргумента при каждом применении этой функции. При полиморфизме включения объект можно рассматривать как принадлежащий многим различным классам, не обязанным быть непересекающимися, то есть может иметь место вложение классов. Эти два представления универсального полиморфизма взаимосвязаны, но достаточно существенно отличаются практически и теоретически, чтобы заслужить различные названия.
Функции, обладающие параметрическим полиморфизмом, также называются обобщенными, или generic-функциями. Например, функция длины (length), принимающая значения из списка произвольных типов и возвращающая целые числа, называется обобщенной функцией длины. Обобщенная функция – это такая функция, которая может работать с аргументами различных типов, в общем случае выполняя одну и ту же работу независимо от типа аргумента. Если рассматривать обобщенную функцию как одно значение, она будет иметь много функциональных типов, и, таким образом, будет полиморфной. Обобщенные функции Ada – особый случай этой концепции.
Есть также два основных типа перегрузок. При перегрузке одно и то же имя используется для разных функций, и то, какая функция соответствует конкретному имени, определяется по контексту. Можно предполагать, что при предварительной обработке программы перегрузка будет удалена, и различным функциям будут присвоены различные имена. В этом смысле перегрузка – это просто удобное синтаксическое сокращение. Приведение типов (coercion) – это, наоборот, семантическая операция, необходимая для того, чтобы преобразовать аргумент в тип, которого ожидает функция, в ситуации, которая иначе привела бы к ошибке. Приведения типов могут быть реализованы статически, путем их автоматической вставки в код во время компиляции, или динамически, при проверках типов аргументов во время исполнения.
Различие между перегрузкой и приведением в некоторых ситуациях размыто. Это в частности верно, когда мы рассматриваем нетипизированный или интерпретируемый язык. Но даже в статически типизированных, компилируемых языках может возникнуть путаница между двумя формами перегрузочного полиморфизма, как показывает следующий пример:
3 + 4
3.0 + 4
3 + 4.0
3.0 + 4.0
Здесь перегрузочный полиморфизм оператора + можно объяснить одним из следующих способов:
§ Оператор + имеет 4 перегруженных варианта, по одному для каждой из четырех комбинаций типов аргументов.
§ Оператор + имеет 2 перегруженных варианта, соответствующих сложению целых и действительных чисел. Если один из аргументов – типа «целое число», а другой – типа «действительное», аргумент типа «целое» приводится к типу «действительное».
§ Оператор + определен только для сложения действительных чисел, и целые аргументы всегда будут приводиться к соответствующим значениям действительных чисел. В этом примере одно и то же выражение можно рассматривать как представляющее и перегрузку, и приведение типов, и как оба сразу, в зависимости от реализации.