Re[32]: «Собаку съел»
От: alex_public  
Дата: 27.01.17 21:39
Оценка: 1 (1) +1
Здравствуйте, samius, Вы писали:

_>>А вот разница в видах полиморфизма на таком уровне как раз очень важна. Потому как если в языке доступен только ad-hoc, то это будет вынуждать программистов заниматься многократным размножением одного и того же исходного кода. Кстати, в таких случая иногда вообще уходят в другую сторону и применяют вместо всего этого технику "стирания типов". Например с помощью void* в C или Object в ранней Java. Это всё или не безопасно или медленно, но в любом случае крайне не удобно. Однако предпочитают использовать даже такое, только чтобы не заниматься "копипастой".

S>Вот тут, кстати, написано что void* это небезопасный параметрический полиморфизм во весь рост.

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

Кстати, в C++ имеется своя, полностью безопасная техника стирания типа: http://www.boost.org/doc/libs/1_63_0/doc/html/boost_typeerasure.html. И с помощью неё можно элементарно написать аналог equal_to, который будет демонстрировать параметрический полиморфизм не только на уровне исходного кода, но и на уровне машинного:
typedef any<equality_comparable<>, const _self&> eq;
bool my_equal_to(eq l, eq r) {return l==r;}

Простейший тест будет выглядеть так:
struct Test1 {}; struct Test2 {};
bool operator==(const Test2& l, const Test2& r) {return true;}

my_equal_to(1, 1); //вернёт true
my_equal_to(1, 2); //вернёт false
my_equal_to("1"s, "1"s); //вернёт true
my_equal_to(Test1{}, Test1{}); //ошибка компиляции - типобезопасность сохранена
my_equal_to(Test2{}, Test2{}); //вернёт true

В данном случае функция my_equal_to так же работает с любыми типами имеющими оператор равенства, но при этом она полностью изолирует ad-hoc природу этого оператора внутри себя — она имеет единый и исходный и машинный код для всех типов. По сути похоже на работу внутренностей Хаскеля. И такое же медленное (без всякого инлайнинга). Так что в мире C++ этот механизм используется только для очень специфических целей.

_>>2. Про неизбежность распухания кода из-за ad-hoc полиморфизма. Ты всё время при подобных рассуждениях держишь в уме реализацию шаблонов в C++, но это же не единственный вариант. Т.е. понятно что в любом языке на самом низком уровне (в конце концов это АЛУ процессора) лежит ad-hoc полиморфизм, над которым выстраиваются слои параметрического полиморфизма (если он вообще есть). В C++ при компиляции все эти слои интегрируются ради быстродействия. Но мы же уже видели на примере отдельной бинарной сборки apply в Хаскеле, что есть и другие реализации. Т.е. при такой реализации низкоуровневый ad-hoc полиморфизм (оператор равенства в нашем примере) легко изолируется на своём уровне и никак не влияет на природу equal_to. Более того, подобное можно элементарно реализовать и на C++, причём даже без всякой переделки компилятора (а вот переписать всю STL придётся). Только оно будет в разы медленнее текущей реализации, так что и задаром никому не нужно.

S>На природу equal_to не влияет, но раздувает transform.

В шаблонах C++ — да. В других реализациях (см. например выше) — необязательно. Т.е. основная моя мысль в том, что указанное распухание кода является свойством (является ли оно ужасной проблемой или же важным преимуществом — это другой вопрос) именно шаблонов C++, а не обязательным следствием взаимодействия параметрического и ad-hoc полиморфизма. В других реализациях ad-hoc часть вполне себе изолируется и никак не влияет на другие уровни.

_>>3. Главное. Даже если забыть в какое время мы живём (когда я скачиваю с сайта фильм в blu-ray качестве (18 ГБ) за 20 минут), то увеличение быстродействия в разы уже давным давно окупает любые распухания кода. Более того, практически все компиляторы (любых языков) имеющие вменяемые оптимизаторы на максимальных уровнях оптимизации увеличивают размер кода. Без всяких шаблонов, полиморфизма и т.п. Просто потому что в основе эффективной оптимизации лежит агрессивный инлайнинг. Т.е. вся индустрия (ну по крайне мере та её часть, где быстродействие хоть что-то значит) стремятся двигаться по этому пути, хотя и не всегда выходит (в том же Хаскеле как только не извращаются, но всё равно выходит медленно), т.к. задача сложная и часто эмпирическая. А в шаблонах C++ это всё даётся с гарантией и так сказать на халяву, по построению. И тут ты говоришь об этом самом распухании как о неком недостатке. Забавно. )

S>Не совсем верно. Я не пытаюсь кому-либо советовать, как правильно реализовывать комбинации полиморфизмов. Я лишь пытаюсь привлечь твое внимание к тому, какие проблемы решали в 88, оговариваясь что Eq a — это ad hoc, но в меньшей мере ad hoc, чем просто перегрузка.
S>Ты вообще согласен что Eq a — это ad hoc (о чем написано на каждом заборе)? Если да, то как ты объяснишь свое желание считать equal_to параметрическим, хотя он в большей мере ad hoc, о чем писал Wadler?

Eq a в данном примере является аналогом не equal_to, а всему множеству операторов равенства в данном C++ проекте. ))) А прямой аналог equal_to вряд ли встретится на практике (хотя пишется элементарно) в Хаскеле и ему подобных языках, просто потому что в отличие от C++ данное мелкое украшательство может оказаться не бесплатным. Кстати, бесплатные многоуровневые абстракции — это как раз одна из ключевых особенностей современного C++.

_>>Это миф. Потому как в C# имеется только один механизм языка увеличивающий его выразительность и отсутствующий в C++ (причём это продлится только до выхода следующего стандарта C++), а в C++ имеется целый набор таких механизмов, отсутствующих в C#. Так что описанное тобой выше явление может встретится на практике только в одном редком случае: когда для C# имеется готовая библиотека предметной области, а для C++ нет. Такое бывает в некоторых узких областях, но как ты понимаешь к дизайну языка это никакого отношения не имеет.

S>Это не миф, это результат моего опыта. Да, я в разной степени владею C# и C++. И именно в моем случае скорость развития С++ проекта в разы медленнее, чем скорость развития схожего по сложности проекта на C#.

А, ну если ты только про себя говоришь, то всё может быть. Более знакомым инструментом частенько можно добиться лучших результатов. Даже если сам инструмент хуже по своей природе. )

S>Время компиляции тоже имеет значение. Разработка на C++ в моем случае является драйвером обновления рабочего железа. Как перехожу на C#, я на том же железе могу еще лет 5 комфортно работать.


Это справедливо. )

S>Так что, equal_to — ad hoc?


Которая std::equal_to? На уровне исходных кодов — нет. На уровне машинных — пожалуй. Точнее на уровне машинных кодов её не будет вовсе, а будет только вставленный на место её вызова код оператора равенства (который ad hoc). Я вроде это всё сказал ещё в самом начале дискуссии.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.