Re[18]: IEquatable<T>
От: samius Япония http://sams-tricks.blogspot.com
Дата: 19.02.17 18:40
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, samius, Вы писали:


S>>Что всё? Дотнет нейтив? Ну будет на худой конец компилятор указывать тип компарера.


V>Не будет до тех пор, пока ограничения генериков не станут частью типа.

Что мешает?


V>>>>>Это отказ от обсуждения систем типов и возможностей параметрического полиморфизма? ))

S>>>>List<T> параметрически полиморфен. Что тут еще обсуждать?

V>>>Обсуждалась система типов + курьёзы, связанные с т.н. "типизированным параметрическим полиморфизмом", при попытке использовать его в стиле тру-ООП, когда разработчики такой системы типов решают облегчить себе жизнь.

V>>>Не работает это...
S>>Твой курьез не сработал. Я написал IndexOf извне класса и система типов пережила это.

V>Да ничего ты не написал. ))

V>У тебя нет самой возможности писать конкурирующие специализации в C#, типа таких:
Так ты хотел именно конкурирующие специализации? Извини, из твоих постов я это не понял. А к чему они нужны, что они доказывают?
V>
V>class MyExtentions 
V>{
V>    public int IndexOf<T>(IList<T> list, T value) {}
V>    public int IndexOf<T>(IList<T> list, T value) where T : IEquatable<T> {}
V>}
V>


V>В С++ такой трюк возможен, в Хаскеле возможен, в C# — нет.

Верно, нет. Но если бы было возможно, это был бы ad-hoc. Так к чему это все?

V>>>В общем, я тут больше отвечал тем, кто считает, что в С++ обитает "неполноценный параметрический полиморфизм".

S>>Конечно обитает. И полноценный параметрический там тоже обитает.

V>Тут просто надо помнить, в чем был аргумент этих горе-обвинителей. По их мнению, "полноценный" — это который работает на рекурсивно-определяемых типах. Правда, эти обвинители не обратили внимание, что ограничение на рекурсивно-определяемые типы в С/С++ никак не связаны с параметрическим полиморфизмом, что последний унаследовал исходные возможности объявления типов языка.

Вот зачем ты мне рассказываешь про каких-то горе-обвинителей? Они не смогли оценить твою победу над ними и ты хочешь что бы я сделал это за них? Их аргументов я не видел, отвечать за них не буду. Разделить твою победу тоже не могу.

V>>>Там, где ты рядом скипнул, содержалась полная инфа относительно вида параметрического полиморфизма в С++ (он имеет вполне определённую классификацию — т.н. "нетипизированный параметрический полиморфизм"), а так же объяснял, как легко и непринуждённо из нетипизированного сделать типизированный, причем, более полноценный, чем "тру параметрический полиморфизм" в дотнете.

S>>С IEquatable ты там кучу кода написал, но од ad-hoc не ушел и к чистому параметрическому не пришел.

V>Так я там и показал совместную работу двух видов полиморфизма — я продемонстрировал, как породить специализацию для ограниченного семейства типов из изначально неограниченного. А чтобы было понятней — я сделал это ограничение аккурат на манер дотнета, а именно — указал в кач-ве ограничения базовый класс.

Дотнет тоже умеет использовать ad-hoc.

V>Так-то в С++ можно придумать овердохрена способов всевозможнейших ограничений.

V>См. type traits и function traits.
Ну можно.

V>>>Нужна, но это невозможно для ситуации, если речь идёт об автоматически подставляемом компилятором генерик-компараторе. Тут даже не важно, value-type или ref будет этот компаратор. Соответствующий сниппет я уже приводил. Не компиллируется.

S>>Он не компилируется лишь от того, что ты вкорячил его в List<T>, которому не захотел ограничивать T.

V>Я не "не захотел". Я не смог.

V>И ты не сможешь.
V>Потому что нельзя породить несколько версий List<T> с разными ограничениями на T. Или в одном List<T> нельзя давать методы с разными ограничениями на T.
А ЗАЧЕМ?


S>>Если вынести — все компилируется. Но это все равно ad-hoc.


V>Курьёз в том и состоит, что как пример ad hoc-полиморфизма ты мне приводил в Хаскеле как раз те примеры, где ограничение на тип является частью полиморфного типа.

Какая разница? elem — ad hoc. IndexOf — ad hoc. Что именно меняет то, на что ты упираешь?

V>Т.е., курьёз у тебя происходит классический: тут смотрим, тут не смотрим, тут рыбу заворачиваем. ))

И там и там смотрим — видим ad-hoc. Рыба у тебя какая-то с параметрическим elem.

V>В Хаскеле для ad hoc полиморфизма тебе потребовалось ограничение внести в систему типов, в C# уже не требуется, "это всё равно ad-hoc".

V>Сорри, детсад.
Детсад — это утверждение что система типов каким-то образом влияет на то, ad hoc или нет. Покажи, откуда это вообще следует?
V>В случае обеих языков ad hoc происходит не там.
нене, языки тут не при чем. Это в твоей голове ad hoc происходит не там.


V>>>Это не мне. Это системе типов дотнета.

V>>>В Хаскель и С++ запросто сделать отдельные специализации для IEquatable<> и для любых других мыслимых "концептов".
S>>Специализации! слово-то какое. Прям — ad-hoc.

V>Верно.

V>Просто не надо путать "специализацию" и "ad-hoc полиморфизм".
Как раз надо. Специальное знание о типе — и есть ключевое отличие от параметрического, где это знание не требуется.

V>Я сразу же тебе и сказал, что ad-hoc полиморфизм достигается через специализацию.

Разве ж я с этим спорил?

V>Но не обязательно через специализацию достигается сам полиморфизм. Чаще всего (уже обращал твоё внимание) специализация нам нужна для типизации "черного ящика" до "концепта". Что такое "концепт" тоже говорил уже — это такой "черный ящик", для которого дан набор операций.

Вот набор операций — это уже специализация. Параметрический полиморфизм не требует набора операций.

V>>>Речь сугубо о выразительности библиотек, об отсутствиии необходимости плодить ручную работу (клонирование) — рядом приводил уже ссылки на автогенерённый код, повторить ссылки? В общем, с учётом обсуждения рядом Net Native и ограничений на рефлексию — вопрос не праздный.

S>>Да уперся ты в рефлексию!

V>Я привел её как пример дурных следствий из недоработанной системы типов дотнета.

V>Если бы были допустимы конкурирующие определения для IndexOf, данные мною выше в этом же посте, то никакая рефлексия была бы не нужна.
V>Хаскель же как-то работает без рефлексии?
Ну пусть система типов дотнета недоработана. Я с этим не спорю. Я лишь утверждаю что это не имеет отношения к ad hoc/параметричности полиморфизма.

V>>>Кодогенерацию через T4? ))

S>>Тоже не повлияет на классификацию

V>Ну я-то не на классификацию пытаюсь повлиять, а на тебя. ))

V>Потому что так смешно вышло, что в дотнете отсутствуют те ср-ва, которые ты назвал необходимыми и достаточными для ad hoc полиморфизма в Хаскеле. Неужели в дотнете нет ad hoc полиморфизма? ))
Жжошь напалмом! Есть в дотнете. Перегрузка операторов и функций, приведение типа, переопределение виртуальных методов, ограничения дженериков. И это все ad hoc. Аналогом хаскелевский классов типа я считаю ограничения дженериков. Кстати, обращу твое внимание, Хаскель появился двадцать с лишним лет спустя после введения классификации Стрэчи. По-твоему до этого не было языков с ad hoc полиморфизмом?

V>Или неужели ты не видишь, к чему я давно клоню — что раз в дотнете есть ДРУГИЕ ср-ва для организации ad hoc полиморфизма, чем упомянутый трюк в Хаскель-вики, так может, признаком ad hoc является что-то другое?

Конечно, является. Как ты догадался? В вики прочитал?

V>>>Тогда можно было бы использовать т.н. "специализацию" (ad hoc), чтобы иметь возможность автоматически распространять ограничения текущего контекста вычислений для низлежащего вызываемого кода.

S>>Напиши код, плиз. Только подробно, чего ты хочешь добиться, и почему это не получается.

V>Одного объявления мало, что ле?

V>Ну вот с телами:
V>
V>static class MyExtentions 
V>{
V>    static public int IndexOf<T>(this IList<T> list, T value)
V>    {
V>        for (int i = 0; i < list.Count; i++)
V>            if (Object.Equals(list[i], value))
V>                return i;

V>        return -1;
V>    }

V>    static public int IndexOf<T>(this IList<T> list, T value) where T : IEquatable<T>
V>    {
V>        for (int i = 0; i < list.Count; i++)
V>            if (list[i].Equals(value))
V>            return i;

V>        return -1;
V>    }
V>}
V>


V>И вот никакая динамическая диспетчеризация через абстрактный компарер уже не требуется для большинства сценариев.

V>А значит, не требуется и кодогенерация через T4 под эти сценарии.
Все стало только хуже.
Итак, предположим что это работало бы в дотнете. (я вообще не против такой возможности, я просто не понимаю, какое отношение она в твоей голове имеет к ad-hoc). Одна диспетчеризация производится компилятором в момент проверки наличия ограничения для конкретного T. Уже диспетчеризация и уже использование специального знания о T. Уже ad-hoc как с выбором оверлоад метода. Далее, в первом методе идет вызов Object.Equals, который обращается к виртуальному методу Equals. Еще одна диспетчеризация, но уже времени выполнения. Второй метод с ограничением указывает на то, что для значения типа T определен СПЕЦИАЛЬНЫЙ код для выполнения сравнения. Тут ad-hoc полиморфны все варианты без вариантов.

V>>>Сейчас же в дотнете НЕТ никакой возможности распространить такие ограничения дальше.

V>>>И не надо защищать систему типов C# только за то, что это C#. Будь объективен.
S>>Я не защищаю (пока). Я просто понять пока не могу, что не так с IndexOf, который вне списка.

V>А какая разница, внутри или вне?

Я же тебе об этом и говорю.
V>Если сделать как показал выше, то получим ошибку:
V>

V>error CS0111: Type 'MyExtentions1' already defines a member called 'IndexOf' with the same parameter types

Так убери конкурирующую специализацию или переобзови ее другим именем. Получишь 2 метода, у которых ad-hoc полиморфизм, но хоть они будут компилироваться и работать.

V>Если разнести эти определения по разным MyExtentions1 и MyExtentions2 и потом попытаться использовать ad-hoc полиморфизм на IndexOf:

Ты не можешь его попытаться использовать. Ты можешь его попытаться не использовать, но от ad-hoc ты никак не отделаешься. IndexOf обречен, т.к. сравнивает экземпляры/значения. Все что сравнивает — делает это специальным образом для каждого типа. И любой тип, который ты подашь в IndexOf, будет требовать специального сравнения, а значит, специального кода для типа T. Не говоря об ReferehceEquals. И вот уже то, что для разных типов по-разному — уже указывает на ad hoc.

V>>>Речь идёт вот о такой предполагаемой фишке:

V>>>
V>>>class List<T> : IList<T> 
V>>>{...}

V>>>class List<T> : IList<T> where T : IEquatable<T> 
V>>>{...}
V>>>

V>>>Разные типы. Пример совместной работы ad hoc и параметрического полиморфизма (рядом ты тоже малость путал одно с другим).
S>>Нету тут совместной работы. Потрял квантор всеобщности у T => нет параметрического полиморфизма.

V>Нет, не потерял. Параметрический полиморфизм НЕ требует работы ф-ии на ЛЮБЫХ входящих типах. Достаточно работы на более одном типе.

ЧТО??? По-твоему любая мономорфная функция параметрически полиморфна?


S>>То что получилось — специализация через ограничения. А это ad-hoc.


V>Тем не менее, методы каждой из версий класса List<T> параметрически полиморфны прямо по-определению параметрического полиморфизма.

Это не так. И даже для невыдуманного List<T>. BinarySearch, Contains, IndexOf, LastIndexOf — ad hoc.
V>Итого — совместная работа.
На разных наборах методов.

V>>>Или вот о такой:

V>>>
V>>>class List<T> : IList<T> 
V>>>{
V>>>    public IndexOf(T value) {}

V>>>    public IndexOf(T value) where T : IEquatable<T> {}
V>>>}
V>>>

V>>>Разные методы, опять совместная работа разных видов полиморфизма.
S>>Вынеси метод и все будет.

V>Вынес. Ничего не было.

Так тебе же все сразу...


S>>В Хаскеле список не тащит ограничений на тип элемента.


V>Я показал рядом пример с методами-расширениями в C#. Не компилируется.

Только потому что тебе нужна перегрузка и с ограничением и без одновременно. Естественно. Но это ничего не меняет в отношении ad hoc.


V>>>Обрати внимание, что в дотнете последняя техника особо мощно смотрелась бы в сочетании с техникой методов-расширений. Это была бы просто киллер-фича, натурально.

S>>Я тебе предложил метод расширение IndexOf, но не пойму, что ты от него нос воротишь.

V>До тех пор, пока не компилируется, имею право, как бэ. ))

Право имеешь.


V>>>А то сейчас на код методов-расширений порой без слёз не взглянешь, когда они пытаются через рефлексию отделить массив от List<T> и от IEnumarable<T>. Согласен, порой и такое полезно, когда произошло стирание типа аж до IEnumerable<>, но уж в случае более полных специализаций можно было бы подставлять совсем эффективный код.

S>>Не понял, где там рефлексия в отделении массива от IEnumerable<T>.

V>В реализации системных библиотек Linq.

V>Происходит рантайм-проверка типа аргумента и ветвление алгоритма.
Ах, вот что ты называешь рефлексией? Ну делалось бы это через visitor... Что бы изменилось? Один хрен ad hoc. (ой, чувствую, щас начнется)


V>Будь внимательней, я говорил о всяких классификациях внутри 1-го ранга одного лишь параметрического полиморфизма.

V>А плане ad hoc полиморфизма разногласий обычно нет.
V>Ты первый. )))
После хаскельвики и просто вики?


V>>>В дотнете ограничения на тип НЕ являются частью типа. Ну вот попытайся ты хаскелистам объяснить, как так у вас вышло, что параметрические аргументы методов или типов навроде `Eq a` и `Num a` с т.з. системы типов неразличимы.

V>>>Услышишь много интересного.
S>>не распарсил

V>А зря. По всей этой ветке это был тот самый единственный, который необходимый и достаточный аргумент, дающий исчерпывающий мой поинт относительно проблем параметрического полиморфизма в C#.

Мы пока еще не договорились по поводу того, что считать параметрическим. Ты привел примеры ad hoc. И в C# они тоже ad hoc.

V>ОК, вот точный аналог упомянутого в дотнете:

V>
V>static class MyModule 
V>{
V>    static public T Foo<T>(T value) where T : Eq<T> {}

V>    static public T Foo<T>(T value) where T : Num<T> {}
V>}
V>

V>В дотнете такое не компиллируется.
V>А в Хаскеле подобный сценарий — это основа основ современных практик для этого языка.
Пусть, но это ad hoc. И если бы скомиплилось в дотнете, все равно им бы оставалось.


V>>>Просто нашел собеседника, которому можно подобное озвучивать и он достоверно поймёт, о чем речь. ))

S>>Ошибся, походу.

V>Да уж...

Точно.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.