Skip to content

Latest commit

 

History

History
77 lines (53 loc) · 9.17 KB

polymorphism-and-dispatching.md

File metadata and controls

77 lines (53 loc) · 9.17 KB

Диспетчеризация и полиморфизм

Telegram: @piratestories | Гайд | Книги | Статьи, доклады, ресурсы |

Существует целая куча относительно связанных понятий, которые перепутаны так, что черт ногу сломит.

Полиморфизм и его типы:
— Параметрический
— Подтипов (Включения)
— Ad-Hoc (Специальный)

Так же полиморфизм делится на типы по способу имплементации:
— Статический
— Динамический

Далее идет диспетчеризация:
— Статическая
— Динамическая

И последнее — это связывание:
— Раннее
— Позднее

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

Полиморфизм — это понятие из теории типов, а не из ООП, как многие считают. В истинном своем значении оно означает вызов ОДНОГО кода, для РАЗНЫХ типов. Например, мы соединяем два списка, и нам неважно, что там внутри списков, мы не афектим эти данные. Функция, которая аппендит списки принимает на вход не List"Int", а List"T". То есть она не зависит от того чем параметризуется (параметрический!) тип List a. Такой вид полиморфизма в computer science называется — параметрический полиморфизм.

Как нам получить параметрический полиморфизм? Нужно применить мономорфизацию, тоесть, в простейшем случае, создать мономорфные функции. Очевидно, что это дуализм? Мономорфная/полиморфная. Мономорфная работает с конкретным типом. Полиморфная работает с множеством типов.

Мономорфизация — это довольно простая операция. Компилятор тупо генерирует все нужные функции для всех типов и подставляет куда надо. Но, что делать, когда надо сгенерировать 10 тысяч функций? Будет так компилятор делать? Наверное, нет.

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

Полиморфизм подтипов

Другой вид полиморфизма — полиморфизм подтипов. Он обозначает вызов РАЗНОГО кода для ПОДТИПОВ одного типа. Именно это имеется в виду, когда говорят про полиморфизм в ООП. Полиморфизм подтипов чаще всего динамический. Динамический полиморфизм, он же динамическая диспетчеризация, обычно реализован посредством v-table, но не обязатаельно! Виртуальные функции — это всего лишь один из способов его реализации.

Например:object.method(). На этапе компиляции известно, что за метод будет вызван? Нет, конечно. Это зависит от того, что за object там окажется. Надеюсь, как работает виртуальная таблица, понятно. В runtime языка есть таблицы, как в базе данных, в которых содержатся списки классов и методов. Когда мы пишем: obj.method(), то на самом деле это: Class.method(obj) (obj — он же this).

v-table — типичный способ реализовать динамическую диспетчеризацию (см. СИКП, глава 2).

Такое поведение взято в javascript из scheme. Ключевую роль в современном ооп, не считая систему типов, играет динамическая диспетчеризация. Если вы ее выкините, то не сможете пользоваться так, как привыкли и хотели бы языком.

Динамическая диспетчеризация реализуется и другими способами. Например, мультиметоды в clojure. Кроме этого, диспетчеризация бывает еще одиночная и множественная. Мультиметоды — это пример множественной диспетчеризации. В ооп языках она осуществляется по типу. То есть, это почти всегда одиночная динамическая диспетчеризация по типу. obj.method() — фукнция будет выбрана в зависимости от типа obj.

Ad-Hoc полиморфизм

Ad-Hoc полиморфизм самый простой. В зависимости от типов аргументов, применяется разная реализация какой-либо операции.

1 + 2; // 3
'cat' + 'box'; // catbox

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

Итак, late binding.

Позднее связывание и передачу сообщений Алан Кей называет ключевой идеей ооп. Динамическая диспетчеризация != late binding. Хотя позднее связывание неявно подразумевает динамическую диспетчеризацию, это совсем разные понятия, так как ДД не подразумевает late binding! Позднее связывание дает возможность, которая позволяет без остановки проводить операции "на живую". this в javascript — это late binding!

f = () => { f2() }
[Function]
f2 = () => { console.log("ehu") }
[Function]
f()
ehu
undefined
f2 = () => { console.log("ehuhu!!!!") }
[Function]
f()
ehuhu!!!!
undefined

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

Пример. Представьте себе рабочую систему, которая прямо сейчас где-то работает. Вдруг выясняется, что какой-то модуль работает неправильно. Но, это система, которой нельзя лажать! Вы к ней подключаетесь правите этот модуль (не файл, а код загруженный в память, прямо из репла) и он начинает работать. Вот, что дает экстремальное позднее связывание. То, на что ссылается любое имя, вычисляется каждый раз заного и в любой момент может поменяться.

Статическое оно же раннее.
Позднее оно же динамическое.
Но! Это совершенно не связано с понятием динамическая/статическая диспетчеризация.

Источник: https://github.com/Hexlet/hexlet-slack-archive/wiki/Полиморфизм-и-диспетчеризация-(%23computer_science)-17.06.2016