Логиката на функцията трябва да се задава с това, какви типове аргументи и подаваме, а не да я override-ваме или overload-ваме (второто е друг тип полиморфизъм – Ad hoc).
За разлика от Ad hoc полиморфизмът, където имаме същата функция, пренаписана (overloaded) повече пъти, според това какъв тип аргументи и подаваме.
Примерно, ако не задаваш типа на входните параметри, както до скоро беше по принцип в PHP, можеш да използваш една и съща функция за например събиране на числа или конкатениране на стрингове…
Това е особено лесно например в JavaScript, където операторът „+“ служи и за двете.
Но това не е са добри примери за Parametric Polymorphism, защото изискването е да се спазва т.н. type safety.
… parametric polymorphism is a way to make a language more expressive, while still maintaining full static type-safety…
Идеята на Parametric Polymorphism НЕ Е да имаме пълна либералност на това, какво подаваме като тип на параметрите, а по-скоро да разширим областта от възможни типове но така, че логиката вътре във функцията да е една и съща без значение какъв конкретно тип параметри подаваме. Под „да разширим“ се има предвид, да имаме т.н. ковариантност на входните типове.
Toест, не да можем да подаваме каквото си искаме, това би било т.н. Ad hoc plymorphism, което си е едно към едно overloading.
Following Christopher Strachey, parametric polymorphism may be contrasted with ad hoc polymorphism, in which a single polymorphic function can have a number of distinct and potentially heterogeneous implementations depending on the type of argument(s) to which it is applied.
Защото това например НЕ Е Parametric Polymorphism:
function add($a, $b)
{
if ((gettype($a) === 'string') && (gettype($b) === 'string')) {
return $a . $b;
}
if ((gettype($a) === 'integer') && (gettype($b) === 'integer')) {
return $a + $b;
}
}
Нито пък това, което би било Ad hoc и го давам като неработещ пример, защото както знаем в PHP оверлоудване не се поддържа:
function add(int $a, int $b): int
{
return $a + $b;
}
function add(string $a, string $b): string
{
return $a . $b;
}
За PHP специално, добър пример би бил използването на SOLID принципът Dependency Inversion, при който изискваме абстракция, а не конкретна функционалност за тип на входен параметър. Тоест, подаваме на една функция различни обекти но от един и същ интерфейс или абстрактен клас, и тези подадени обекти съответно правейки различни неща, определят поведението на функцията.
interface CacheableInterface
{
public function getCacheKey(): string;
}
class ProductClass implements CacheableInterface
{
public function getCacheKey(string $id): string
{
return 'product_' . $id;
}
}
class CategoryClass implements CacheableInterface
{
public function getCacheKey(string $id): string
{
return 'category_' . $id;
}
}
function store(CacheableInterface $cacheable): string
{
return $cacheable->getCacheKey('ABC-120-3G');
}
Вижда се как на store() може да подаваме различни обекти, стига да са от интерфейс CacheableInterface и съответно, тези отделни обекти имат свое виждане за това, което извеждат. От там идва и различното поведение на store()
Друго, което можем да забележим, че Parametric Polymorphism доста прилича на Subtype Polymorphism, защото горният пример би бил добър и за Subtype Polymorphism ако имахме и йерархия от класове.
Добър въпрос би бил, каква е разликата между Parametric Plymorphism и Subtype Polymorphism?
При Subtype Plymorphism трябва да имаме йерархия на типовете, например на класовете или на примитивните типове (float, int…).
При Parametric Polymorphism – не. Както се вижда от горният пример, няма йерархия между взаимозаменяемите ProductClass и CategoryClass, между тях самите, нищо че имплементират общ интерфейс.
Затова Parametric Polymorphism е по-общият случай на Subtype Polymorphism.
Литература:
https://sergeyzhuk.me/2017/04/09/oop-polymorphism/
https://en.wikipedia.org/wiki/Parametric_polymorphism