Информация об изменениях

Сообщение Re[16]: Concept-Based Polymorphism от 19.07.2020 6:30

Изменено 19.07.2020 6:44 so5team

Re[16]: Concept-Based Polymorphism
Здравствуйте, B0FEE664

Разговор, который начинался для выяснения того, что вы понимаете под "параметрическим полиморфизимом" начинает перерастать в спор о том, чьи определения полиморфизма должны считаться правильными. По ряду причин у меня нет ни возможности, ни желания развивать этот спор. Поэтому предлагаю закончить, т.к. я выяснил то, что мне было нужно.

Но, т.к. моя точка зрения могла остаться недопонятой, то тезисно по основным пунктам.

От классификации зависит понимание предмета собеседниками. Если у каждого из нас собственное представление о "параметрическом полиморфизме", то когда вы говорите "у меня в коде используется параметрический полиморфизм", то я ваши слова буду воспринимать совершенно не так. И наоборот.

Динамический полиморфизм в С и в C++ приниципально один и тот же. Различия лишь в том, что в C поддержка динамического полиморфизма полностью лежит на программисте, тогда как C++ предоставляет языковые средства для нее.

Типов полиморфизма, с которыми мне доводилось иметь дело, три:

Ad-hoc полиморфизм. В C++ реализуется как перегрузка:
bool equal(const char * a, const char * b);
bool equal(const std::string & a, const std::string & b);
bool equal(int a, int b);
bool equal(float a, float b);


Параметрический полиморфизм. В C++ реализуется в виде шаблонов:
template<typename T> bool equal(const T & a, const T & b) {...}
template<typename T> T min(T a, T b) {...}


Динамический и subtyping полиморфизм. В C++ реализуется из коробки через наследование с виртуальными методами. Либо же может быть реализован вручную на указателях на функции или std::function. Но традиционно понимается как наследование с виртуальными методами.

При этом в C++ термин "статический полиморфизм" является синонимом "параметрическому полиморфизму". Просто так сложилось. Поскольку перегрузка функций в C++ была с самого начала, еще до того, как термин "полиморфизм" вообще пришел в массы и в мире C++ перегрузку функций как полиморфизм рассматривают далеко не все C++ программисты.

Не трудно заметить, что и Ad-hoc, и параметрический полиморфизмы разрешаются в compile-time. Поэтому они оба могут называться "статическим полиморфизмом". Из-за чего сам по себе термин "статический полиморфизм" (в отрыве от C++ где у него исторически один смысл) не точный, за ним могут скрываться принципиально разные вещи.

То, что в случае с параметрическим полиморфизмом компилятор может сгенерировать разный код для разных типов параметров с точки зрения разновидностей полиморфизма роли не играет. Т.е. разработчик имеет дело только с исходным кодом, который оказывается один вне зависимости от типа параметров.

Сигнатура функции определяет тип функции. Поэтому, если у вас есть void(*)(), то уже без разницы, указатель на какие именно функции вы будете туда помещать. Поскольку вот это:
void say_hello() {...}
void format_disk() {...}

using pfn = void (*)();

void consume(pfn fn);

pfn a = say_hello;
pfn b = format_disk;

consume(a);
consume(b);

ничем не отличается вот от этого:
void consume(int v);

int a = 1234/45 + 56;
int b = 56 - 345/7 + 12*9;

consume(a);
consume(b);

Поскольку оба фрагмента завязаны на конкретные типы: в первом случае на void(), во втором на int. Но типы зафиксированы, а то, что у экземпляров этих типов разные значения, то это обычное дело.

Параметрический полиморфизм бы здесь появился если бы consume научился бы брать разные типы. В случае с функциями consume должен бы был воспринимать не только void(), но и, скажем, int() или void(char*).

Детали реализации механизма слотов не важны по той же самой причине, по которой в математике не важно считаете ли вы количество яблок, количество палочек на парте или количество черточек, нарисованных на доске. Важно лишь то, что 2+2=4, вне зависимости от того, количество чего обозначено числами "2". Разница на первых этапах обучения существует только у детей, для которых подсчитывание палочек на парте и черточек на доске может выглядеть принципиально разными занятиями. Но по мере обучения развивается абстрактное мышление и эта разница исчезает.

Поэтому принципальное значение с точки зрения архитектуры является применение абстракции "слот". Детали же реализации "слота" на архитектуру влияния не оказывают, т.к. эти детали рассматриваются несколькими уровнями ниже.
Re[16]: Concept-Based Polymorphism
Здравствуйте, B0FEE664

Разговор, который начинался для выяснения того, что вы понимаете под "параметрическим полиморфизимом" начинает перерастать в спор о том, чьи определения полиморфизма должны считаться правильными. По ряду причин у меня нет ни возможности, ни желания развивать этот спор. Поэтому предлагаю закончить, т.к. я выяснил то, что мне было нужно.

Но, т.к. моя точка зрения могла остаться недопонятой, то тезисно по основным пунктам.

От классификации зависит понимание предмета собеседниками. Если у каждого из нас собственное представление о "параметрическом полиморфизме", то когда вы говорите "у меня в коде используется параметрический полиморфизм", то я ваши слова буду воспринимать совершенно не так. И наоборот.

Динамический полиморфизм в С и в C++ приниципально один и тот же. Различия лишь в том, что в C поддержка динамического полиморфизма полностью лежит на программисте, тогда как C++ предоставляет языковые средства для нее.

Типов полиморфизма, с которыми мне доводилось иметь дело, три:

Ad-hoc полиморфизм. В C++ реализуется как перегрузка:
bool equal(const char * a, const char * b);
bool equal(const std::string & a, const std::string & b);
bool equal(int a, int b);
bool equal(float a, float b);


Параметрический полиморфизм. В C++ реализуется в виде шаблонов:
template<typename T> bool equal(const T & a, const T & b) {...}
template<typename T> T min(T a, T b) {...}


Динамический или subtyping полиморфизм. В C++ реализуется из коробки через наследование с виртуальными методами. Либо же может быть реализован вручную на указателях на функции или std::function. Но традиционно понимается как наследование с виртуальными методами.

При этом в C++ термин "статический полиморфизм" является синонимом "параметрическому полиморфизму". Просто так сложилось. Поскольку перегрузка функций в C++ была с самого начала, еще до того, как термин "полиморфизм" вообще пришел в массы и в мире C++ перегрузку функций как полиморфизм рассматривают далеко не все C++ программисты.

Не трудно заметить, что и Ad-hoc, и параметрический полиморфизмы разрешаются в compile-time. Поэтому они оба могут называться "статическим полиморфизмом". Из-за чего сам по себе термин "статический полиморфизм" (в отрыве от C++ где у него исторически один смысл) не точный, за ним могут скрываться принципиально разные вещи.

То, что в случае с параметрическим полиморфизмом компилятор может сгенерировать разный код для разных типов параметров с точки зрения разновидностей полиморфизма роли не играет. Т.е. разработчик имеет дело только с исходным кодом, который оказывается один вне зависимости от типа параметров.

Сигнатура функции определяет тип функции. Поэтому, если у вас есть void(*)(), то уже без разницы, указатель на какие именно функции вы будете туда помещать. Поскольку вот это:
void say_hello() {...}
void format_disk() {...}

using pfn = void (*)();

void consume(pfn fn);

pfn a = say_hello;
pfn b = format_disk;

consume(a);
consume(b);

ничем не отличается вот от этого:
void consume(int v);

int a = 1234/45 + 56;
int b = 56 - 345/7 + 12*9;

consume(a);
consume(b);

Поскольку оба фрагмента завязаны на конкретные типы: в первом случае на void(), во втором на int. Но типы зафиксированы, а то, что у экземпляров этих типов разные значения, то это обычное дело.

Параметрический полиморфизм бы здесь появился если бы consume научился бы брать разные типы. В случае с функциями consume должен бы был воспринимать не только void(), но и, скажем, int() или void(char*).

Детали реализации механизма слотов не важны по той же самой причине, по которой в математике не важно считаете ли вы количество яблок, количество палочек на парте или количество черточек, нарисованных на доске. Важно лишь то, что 2+2=4, вне зависимости от того, количество чего обозначено числами "2". Разница на первых этапах обучения существует только у детей, для которых подсчитывание палочек на парте и черточек на доске может выглядеть принципиально разными занятиями. Но по мере обучения развивается абстрактное мышление и эта разница исчезает.

Поэтому принципальное значение с точки зрения архитектуры является применение абстракции "слот". Детали же реализации "слота" на архитектуру влияния не оказывают, т.к. эти детали рассматриваются несколькими уровнями ниже.