Введение

Применение полиморфных функций к аргументам разных типов

В языках программирования, ad hoc полиморфизм – это вид полиморфизма, при котором полиморфные функции могут применяться к аргументам различных типов, поскольку полиморфная функция может представлять собой ряд различных и потенциально разнородных реализаций в зависимости от типа аргумента (ов), к которым она применяется. Применительно к объектно-ориентированным или процедурным концепциям, он также известен как перегрузка функций или перегрузка операторов. Термин ad hoc в данном контексте не имеет негативного оттенка; он лишь указывает на то, что этот тип полиморфизма не является фундаментальной характеристикой системы типов. Это противопоставляется параметрическому полиморфизму, в котором полиморфные функции записываются без указания какого-либо конкретного типа и, таким образом, могут применять единую абстрактную реализацию к любому числу типов прозрачным образом. Эта классификация была предложена Кристофером Стречи в 1967 году.

Раннее обязательное действие

Ad hoc полиморфизм — это механизм диспетчеризации: управление, проходящее через одну именованную функцию, направляется в различные другие функции без необходимости указывать конкретную вызываемую функцию. Перегрузка позволяет определить несколько функций, принимающих разные типы, с одним и тем же именем; компилятор или интерпретатор автоматически обеспечивает вызов нужной функции. Таким образом, можно написать функции для добавления списков целых чисел, списков строк, списков чисел с плавающей точкой и т. д., и все они будут называться `append` — при этом будет вызываться правильная функция `append` в зависимости от типа добавляемых списков. Это отличается от параметрического полиморфизма, при котором функция должна быть написана обобщённо, чтобы работать с любым типом списка. Используя перегрузку, можно заставить функцию выполнять совершенно разные действия в зависимости от типа входных данных, переданных ей; это невозможно при параметрическом полиморфизме. Другой взгляд на перегрузку заключается в том, что процедура однозначно идентифицируется не только своим именем, но и комбинацией имени, количества, порядка и типов её параметров. Этот тип полиморфизма распространен в объектно-ориентированных языках программирования, многие из которых позволяют перегружать операторы аналогичным функциям (см. перегрузку операторов). Некоторые языки, которые не имеют динамической типизации и не поддерживают ad hoc полиморфизм (включая классы типов), используют более длинные имена функций, такие как `print_int`, `print_string` и т. д. Это можно рассматривать как преимущество (более описательно) или недостаток (чрезмерная многословность) в зависимости от точки зрения. Одним из преимуществ перегрузки является возможность специализации: функция с одним и тем же именем может быть реализована несколькими различными способами, каждый из которых оптимизирован для конкретных типов данных, с которыми она работает. Это может обеспечить удобный интерфейс для кода, который необходимо адаптировать к различным ситуациям для повышения производительности. Недостатком является то, что система типов не может гарантировать согласованность различных реализаций. Поскольку перегрузка выполняется во время компиляции, она не является заменой позднему связыванию, как это встречается в полиморфизме подтипов.

Позднейшее связывание

Несмотря на предыдущий раздел, существуют и другие способы реализации ad hoc полиморфизма. Рассмотрим, например, язык Smalltalk. В Smalltalk перегрузка выполняется во время выполнения, поскольку методы ("реализация функции") для каждого перегруженного сообщения ("перегруженная функция") разрешаются непосредственно перед выполнением. Это происходит во время выполнения, после компиляции программы. Таким образом, полиморфизм обеспечивается как полиморфизмом подтипов, как и в других языках, так и расширяется за счет ad hoc полиморфизма во время выполнения. Более внимательное рассмотрение покажет, что Smalltalk предоставляет несколько иную разновидность ad hoc полиморфизма. Поскольку Smalltalk использует модель исполнения с поздней привязкой, и поскольку объекты обладают способностью обрабатывать неподдерживаемые сообщения, можно реализовать функциональность, используя полиморфизм, без явной перегрузки конкретного сообщения. Хотя это может быть не самой рекомендуемой практикой для повседневного программирования, это может быть весьма полезно при реализации прокси. Кроме того, хотя перегрузка общих методов класса и конструкторов обычно не рассматривается как полиморфизм, существуют более единообразные языки, в которых классы являются полноценными объектами. Например, в Smalltalk классы – это обычные объекты. Это, в свою очередь, означает, что сообщения, отправляемые классам, могут быть перегружены, и можно создавать объекты, поведение которых имитирует классы, без наследования их классов от иерархии классов. Это эффективные приемы, позволяющие использовать мощные возможности рефлексии Smalltalk. Аналогичные возможности существуют и в языках Self и Newspeak.