Корректировка к слайду «Параметрический полиморфизм»:
append(numbers1, numbers2);
append(strings1, strings2);
--
В этом уроке мы поговорим немножко о терминах и о такой вещи, как полиморфизм.
В языках программирования и теории типов полиморфизмом
называется способность функции обрабатывать данные разных типов.
Полиморфизм повышает коэффициент повторного использования кода,
то есть уменьшает дублирование.
Со всеми примерами этих полиморфизмов мы уже встречались, но просто никогда не использовали эти термины.
Вызов ОДНОГО и того же кода для ВСЕХ
допустимых типов (полиморфных) аргументов.
Параметрический полиморфизм в теории типов и у людей, которые часто используют функциональные языки, обычно принято называть словом полиморфизм, что кстати говоря идёт в разрез с тем, что принято у программистов, которые пишут исключительно на объектно-ориентированных языках. Они под словом полиморфизм понимают полиморфизм подтипов.
Давайте представим ситуацию, с которой мы уже сталкивались. У нас есть список и мы вызываем операцию «собрать два списка в один»:
const numbers1 = l(3, 4, 5, 8);
const numbers2 = l(3, 2, 9);
append(numbers1, numbers2); // (3, 4, 5, 8, 2, 9)
append
берет два списка и делает из них один.
Ещё один пример той же самой операции, но разница в том, что теперь здесь список строк:
const strings1 = l('cat', 'dog');
const strings2 = l('table', 'milk', 'phone');
append(strings1, strings2); // (cat, dog, table, milk, phone)
https://repl.it/@hexlet/js-ddp-polymorphism-parametric-polymorphism
Поскольку мы работаем в динамическом языке нам без разницы с какими типами работать. Какой бы список у нас не был и какой бы тип не содержался внутри какого-то основного типа – всё будет работать.
В статических языках это совершенно не так и вы не можете просто так определить список чего угодно. У вас будет список конкретных структур, поэтому в таких языках нужны специальные механизмы, которые позволяют определять обобщённые списки.
Это важно по той простой причине, что применяя функцию append
(операция объединения списков) можно увидеть, что над элементами, которые лежат в списке, никаких действий не производится вообще. Они не участвуют в этой операции и им не нужно это. То есть объединяя два списка мы не делаем никаких преобразований внутри. Соответственно, эта операция в общем случае не зависит от того, что хранится внутри.
Идеально – язык программирования должен позволять нам работать с этим именно так.
Как я уже говорил, в динамических языках мы получаем параметрический полиморфизм из коробки и действительно – функция append
одна для любых списков, потому что мы не делаем здесь никаких различий, код будет один и его будет довольно мало.
В статических языках нет механизма для поддержки параметрического полиморфизма, им придётся писать функцию append
для каждого типа. Представьте себе сколько может быть списков и сколько вообще может быть таких структур, для которых придётся так делать. По этой причине там существуют специальные механизмы.
Особенно эти проблемы существуют в объектно-ориентированных языках, потому что в функциональных языках параметрический полиморфизм есть всегда и из коробки – это основа, а вот например, в таких языках как Java, существует специальный механизм, который называется дженерики. В C++ существует механизм, который называется темплейты.
В каких-то других языках это может называться по другому, но всё это сводится к тому, чтобы иметь возможность пользоваться параметрическим полиморфизмом у себя в языке.
Это самый простой тип полиморфизма. Он связан с тем, что в зависимости от типов аргументов применяется разная реализация какой-то операции.
Например, в данном случае сложения:
1 + 1; // 2
'cat' + 'dog'; // catdog
console.log(1034.98); // => 1034.98
console.log('hello'); // => hello
https://repl.it/@hexlet/js-ddp-polymorphism-ad-hoc-polymorphism
Если у нас типы число и число, то у нас будет арифметическая операция. Если у нас две строчки, то это будет конкатенация. Если будут разные типы, то там уже зависит от ситуации.
Причём в статических языках, опять же, ad-hoc полиморфизм реализуется за счёт перегрузки функций (то есть описываются разные тела функций, в которых задаются разные типы аргументов) и соответственно компилятор сам выбирает какую функцию в какой момент использовать. Внутри нет никаких if’ов, то есть мы уже работаем конкретно с теми типами, которые мы определили в данной функции. Под одним именем одной операции скрывается несколько разных тел.
В динамических языках мы этого делать не можем, поэтому там по сути всегда это сводится к тому, что у вас есть одна функция, внутри которой много if’ов, которые проверяют типы аргументов.
Например, если посмотреть исходники console.log
, можно увидеть, что там это примерно так и устроено. Там используется функция формат, которая внутри проверяет типы аргументов и в зависимости от типа делает какие-то разные действия.
Напомню, что полиморфизм подтипов в объектно-ориентированных языках называют просто полиморфизм, что не совсем корректно.
Как раз этот полиморфизм позволяет вызывать РАЗНЫЙ код для РАЗНЫХ иерархий типов.
const obj = new SimpleCard(); // or PercentCard()
obj.damage(health);
Собственно, с этим полиморфизмом мы сквозь весь наш курс в первую очередь и знакомились и использовали его в нашей программе. И именно задача нашего курса была завести внутри языка полиморфизм подтипов.
Полиморфизм подтипов является ключевой штукой для ООП.
Почему это нужно – мы уже прекрасно знаем. Бывает, что для разных типов нужно вызывать разную реализацию одних и тех же (с точки зрения интерфейса) функций для того, чтобы не писать if
.
Это как раз к вопросу о том, что эта штука исключительно просто сокращает код с точки зрения практики, а формально вы, конечно, можете работать и без него.
Полиморфизм связан с динамической диспетчеризацией, которую мы разбирали. Просто динамическая диспетчеризация – это один из способов реализации полиморфизма.
Любой язык и любая штука, с которой мы работаем, позволяет нам использовать полиморфизм и как раз с помощью динамической диспетчеризации мы можем его, собственно, реализовать и таким образом просто сокращать тот код, который мы пишем.
Вам ответят команда поддержки Хекслета или другие студенты.
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.
Наши выпускники работают в компаниях:
Зарегистрируйтесь или войдите в свой аккаунт