Re[18]: Swift
От: vdimas Россия  
Дата: 10.06.14 08:32
Оценка: -2
Здравствуйте, Ikemefula, Вы писали:

V>>Всё намного проще. Я пока тупо тянул время, бо в эти выходные ни с какой виртуалкой макоси возиться не собирался.


I>Все почти верно, кроме одной детали — тянуть время ты можешь годами, или выдать "пфф любой студент за два часа, мы не в детсаде"

I>Вспомнишь сам или ссылкой дать ?

Да пофиг. На руках было только описание языка. Согласно его описанию вашу задачку можно решить как тем способом, что настаивал D.Mon, так и тем, что настаивал я. Просто, коль уважаемый мной коллега УТВЕРЖДАЛ, что во встроенных массивах нет итераторов (!!! и я ему ПОВЕРИЛ, т.к. еще не прошелся по базовой либе) я предложил ему решение БЕЗ итераторов вообще.

Уверен, он понял, что я предложил, а ты — нет. И не поймешь. Но после того, как он же прилюдно исправился — показывать ЕГО решение отпало смысл. Но можно еще показать моё решение, в стиле ФП, было бы кому интересно... оно ведь и так известно.

В любом случае, даже в отсутствии в базовой либе итераторов, можно было как в С++ — отлучить операторы от языка, описать их в пользовательских типах, а для встроенных массивов или коллекций, итераторы которых по каким-либо причинам не соответствуют итераторам из стандартной либы, можно однократно написать обобщенный миниатюрный хелпер, выдающий наружу требуемые по фасаду итераторы, примерно как это сделано в концепции boost::range:
http://www.boost.org/doc/libs/1_54_0/libs/range/doc/html/index.html

Я понимаю, что для тебя это всё неподъемно, ну уж извини. Я вижу язык, который позволяет делать ТАК ЖЕ, как по ссылке, поэтому не вижу проблему. Ты же знаком только с генериками дотнета, поэтому шаг вправо-влево для тебя "бессмыслица". Ну ОК, знач говорить не о чем, я вижу только бессмысленную рефлексию и топанье ножками. Как же, покусились на священную корову. )))

Что касается ссылки — дай, мне любопытно. Но за 2 часа можно сделать что угодно при уже установленном и настроенном окружении, ес-но. Именно поэтому я дал код на С++ — он просто был под рукой. Я дал часть решения, чтобы показать идею, хоть и не верил, что кто-то кроме тебя не её понял. В любом случае у меня была возможность быстро дать вторую часть решения, если бы кто-то из коллег её попросил. Хотя, я и это считаю откровенным перебором на профессиональном форуме. Идеи решений вообще можно давать на некоем всевдо-языке, какая хрен разница? А кто не вкуривает — пусть идет лесом или на 1C. С ними всё-равно неинтересно — сплошное потреблядство без обмена идеями.
Re[14]: Swift
От: vdimas Россия  
Дата: 10.06.14 08:49
Оценка:
Здравствуйте, Klapaucius, Вы писали:

V>>Если в полноценной реализации, то нужен, ес-но. Но для привычного ООП он почти всегда "недо-", бо идет только по первому аргументу this.

K>Продемонстрированная мной техника это ограничение обходит.

Продемонстрированное тобой решение работает даже в С++, где нет полноценного параметрического полиморфизма. Ууупс?

V>>Ну а что делать, если всё кривое? )))


K>Делать прямым там, где возможно. Обсуждаемое сделать прямым можно одними средствами компилятора, все что для этого нужно (более-менее нормальный полиморфизм, инлайн методов структур и т.д.) CLR уже поддерживает.


Не получится, если компилятор не видит конечный вызываемый тип для генерика. Т.е. "подхватывать" операторы только компилятором не выйдет. ИМХО, JIT должен "знать в лицо" некий IOperators<> и делать всю эту работу сам.

V>>Ты продемонстрировал костыль в условиях "недо-".


K>Это менее костыльно чем всякие "подхватывания". Недоделанность дотнетных дженериков совсем не в этом, а в том, что от конструктора типа нельзя абстрагироваться, нету higher-kinded полиморфизма. Ну так с этим и в сабже проблемы.


Для абстрагирования от конструкторов можно использовать точно такой же трюк как ты показал для операторов. И там и там это статические вызываемые ф-ии. (Надеюсь, ты не станешь попрекать меня тем, что пользовательское тело конструктора является экземплярным методом?)


V>>Нет. Зависимость конкретных типов T->C должна быть неявной. Явное её указание — избыточность, делает решение недо-обобщенным.

K>Явное указание — это, конечно, избыточность, но "недообобщенным" оно решение не делает.

Ну понятно. Дал необобщенное решение и хвалишь.
По мне обобщенное решение — это которое можно использовать изкаробки. Твоё — нельзя. Оно требует дополнительного явного определения под конкретные типы. менно поэтому в базовых либах дотнета показанный тобой трюк не используется, ведь любое решение на нём не будет готово для непосредственного использования.

V>>Можно так:

V>>
V>>T Avg<T>(this IEnumerable<T> xs) where T : INumber<T>, new()
V>>

V>>Как и в Хаскель, собсно. (только с той разницей, что в дотнете INumber<T>, сцуко, описывает контракт только по одному аргументу this... но и этого могло бы хватить для арифметики)

K>Нет, ключевое отличие тут в том, что ":" задает отношение подтипирования, которого в хаскеле нет.


Я бы не говорил так громко, что нет. Классы типов — это и есть аналог подтипирования в ООП, когда речь об абстрактной базе/интерфейсах. И даже можно через механику классов типов накрутить аналог иерархий интерфейсов. Просто оно несколько ортогонально самим типам, которые в хаскеле являются лишь структурами или сигнатурами ф-ий. Но это вопрос терминологии скорее, чем механики происходящего. Фактически идентично в Хаскеле компилятором формируются таблицы для рантайм-полиморфизма, как для виртуальных методов в мейнстримовом ООП.


K>В моем решении его (между T и C) также нет и не должно быть.


Ох, блин... ну и аргументы пошли...
Да какая фиг разница, какой механизм мы использовали для задания отношения двух типов???
Какой механизм был в дотнете, такой я и использовал. Был бы другой механизм — использовал бы другой.

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

V>>Я тебе уже показал абзацем выше аналог на C# того, как это есть в Хаскеле. Заканчивай уже спекулировать.

K>Нет, это не аналог того, что есть в хаскеле. Аналог того, что есть в хаскеле показал я.

Если бы ты показал аналог, тебе не надо было бы явно указывать ComplexReal.


V>>Ес-но, реализация арифметических операторов для Complex должна быть где-то описана. Но не дважды же!


K>Ну так она и не описана дважды:


Дважды, потому что operator+ УЖЕ был однажды описан до этого, а не дан свыше.

K>вызываются библиотечные реализации сложения и деления.


Ну да. Ты пришпилил к готовому публичному интерфейсу ООП-класса еще один фасад. Поздравляю, чо!

K>Если бы мы сами определеяли Complex — могли бы не описывать операции только для Complex, а определить их прямо в имплементации класса. И тот и другой подход используются в хаскеле.


Ну так тогда были бы проблемы с синтаксисом на C#. Ты бы не смог писать привычные a+b. И что мы тогда сравниваем языки. Давай откажемся от операторов вообще, будем описывать формулы через AST и мильон скобок. )))


V>>В Хасклеле бери любую либу с каким-нить MegaComplex, да пользуйся. А в твоём решении на C# надо еще раз по операторам пройтись да продублировать их. Что-то не так в консерватории, не правда ли? ))

K>Очевидно, что надо просто положить инстансы в библиотеку и все, как в хаскеле обычно и делается.

В С++ тоже именно так и делается. Потому что любой оператор в С++ — это ф-ия! Даже оператор присваивания — это ф-ия над lvalue. А в дотнете — только ограниченное подмножество операторов доступно для переопределения и то, с ограничениями даже для такого переопределения.

Получается, что для обсуждаемого здесь класса задач, т.е. как минимум для записи вычислений через привычные операторы, Swift будет намного удобнее C#.


K>Но нередко бывает и так, когда библиотека нужных инстансов не содержит. Тогда пользователь сам описывает инстансы-"сироты". Что собственно я и зделал в своем примере на C#.


Кста! Нечто похожее есть как методы-раширения в C# и Swift. Но, опять же, в дотнете методы-расширения не подхватываются в генериках, а в Swift, насколько я понял — подхватываются.


V>>Ммм... ты действительно не понял пару постов выше намек на то, как это надо было сделать в C#? ))

K>Понял, но я не согласен с тем, что в C# надо так делать. Надо было делать именно как я показал.

А смысл???
Мне пока приходит в голову лишь тот аргумент, что необходимо иметь несколько независимых наборов определений операторов с одним и тем же синтаксисом, но разной семантикой. Правда, сложно представить пользу от этого на примере complex1+xomplex2.

V>>Блин, ты же сам всё правильно говорил про Хаскель! Модель типов дотнета позволяет делать так же. Просто не сделано для встроенных типов.

K>Продемонстрированная мной техника позволяет определять инстансы для любых типов.
K>В хаскеле, кстати, для "встроенных" типов полиморфизм вообще не поддерживается.

Через классы типов + боксирование значений + диспетчеризацию в рантайм этого бокса по тегу завернутого в нем типа — поддерживается аж бегом. Как и в дотнет для value-type, собсно. Сорри, что опять перешел на механику происходящего, но она не сильно-то и отличается. Такой же точно переход по таблице для выборки адреса ф-ии. С той лишь разницей, что в ООП эта таблица принадлежит конкретному типу, а в Хаскеле — конкретному участку кода, где требуется рантайм-полиморфизм, т.е. типу конкретного выражения, ограниченного классами типов (т.е. заданных через "абстрактные" интерфейсы, с учетом специфики ФП языка).


V>>Но даже при этом можно было бы арифметические операторы подхватывать автоматом и на этапе генерации бинарников подставлять в тела генериков нужный код. Даже можно обойтись существующим стандартом на метаинформацию и байт-код, достаточно компилятором генерить фиктивный IOperators<> в байт-коде, а во время JIT-а просто знать этот интерфейс "в лицо" и при его фиктивной реализации просто подставлять статически-переопределенные операторы, тогда тебе не надо было бы ручками описывать свой ComplexReal.


K>Нет уж, лучше написать инстанс руками и положить в библиотеку


Опять и снова вопрос — а переопределенные операторы чем не "инстанс"?

K>а в компилятор универсальный солвер для подстановки любых инстансов, чем встраивать в реализацию компилятора и рантайма какие-то подхватывания избранных операторов.


Ну уж какие есть для переопределения. Не так уж и много.


K>Да даже и без автоподстановки инстансов — все равно лучше.


Чем?


V>>А зачем параметрический полиморфизм в сценариях, где уточненные типы выводятся еще на этапе компиляции?

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

K>Параметрического полиморфизма времени исполнения не существует, он бывает только времени компиляции.


Диспетчеризация, однако, в том же Хаскель зачастую выполняется в рантайм.


K>Этим он от завтипов отличается, для которых полное стирание типов осуществить нельзя.


От сценариев зависит, так же как и у Хаскеля. Где-то разруливает компилятор, а где-то — на этапе исполнения.

V>>Насмешил. В Хаскеле не всегда параметрический полиморфизм нужен в рантайм. 99% сценариев разруливаются на этапе компиляции, т.е. обобщенное программирование в этих сценариях не далеко ушло от С++ — обычная "текстовая подстановка" в итоге. Собсно, даже формат библиотек Хаскеля — это упакованный и размеченный результат парсинга текста (считай тупо AST исходников либы), а не объектный код.


K>Нет, это код, с которым могут поставляются, а могут и не поставляться "развертки", т.е. результат парсинга части кода. Развертки могут использоваться для оптимизации, но все работает и без них — просто медленнее. Это техническая деталь реализации межмодульной оптимизации, реализация параметрического полиморфизма от этого не зависит.


Сам себе противоречишь. Если точные конечные типы можно разрулить на этапе компиляции, то получаем аналог шаблонов С++. Если нет — то у нас рантайм-полиморфизм во всей его кривой красе.

Я когда-то подробно разбирался с Хаскель. Но не с тем, как на нём решать задачи, а как оно работает "унутре". Всё печально, кароч: при экономной записи исходника — в итоге диспетчеризация в рантайм на каждый мало-мальский чих. Даже в случаях, когда казалось бы, что должен применяться обычный ad-hoc полиморфизм, когда просто идет выбор из "глобальных" с т.з. С++, ф-ий, но вместо ad-hoc — рантайм-механика ПМ по аргументу, а имя ф-ии получается как некое обобщение над всеми наблюдаемыми в точке компиляции типами её аргмента... бррр... Поэтому дальнейшего интереса не возникло. Таким языкам еще не время. Нужна суперкомпиляция в её настоящем понимании, чтобы ЭТО взлетело.


K>Упомянутый 1% сценариев — это экзистенциальные типы, там словарь действительно не может быть подставлен в комайл-тайм и ссылка на него хранится в объекте, как в ООП.


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


V>>А конкретно в этой ветке мне постарались надавать по щщам именно из-за попытки сравнения со "священной коровой". Я лишь заметил, что многих проблем C# в Swift нет.


K>Я сильно сомневаюсь, что обсуждаемая проблема в сабже решена нормально, а не в стиле C++.


Обсуждаемой проблемы в Swift нет вообще, как и в С++.

V>>Я не спорю, что до "чистых" языков ему далеко. Это гибрид и как любой гибрид состоит из компромиссов. Но в C# есть даже такие компромиссы, увы, которые вовсе не требовались. И ты наглядно их показал в своей собственной реализации yet another IArithmetic<T>.


K>Похоже на то, что и в сабже таких "компромиссов", которые не требовались, хватает.


Например?

V>>И всё-таки в джаве и дотнете не в языке гвоздь, а в миллионах строк библиотек со сложным, но достаточно надежно оттестированным функционалом.


K>Ну да, правильно.


V>>Хотя для value-типов для тех же генереков JIT генерит код, который нигде по-факту методы интерфейсов не вызывает!


K>Ну, на этом техника и основывается. если бы не это — реализовывать арифметику таким способом не было бы смысла.


V>>Т.е. сие ограничение интерфейсов только на экземплярные методы можно было бы обойти, добавив возможность задавать некий "интерфейс для статических методов", как раз арифметика туда попала бы, а связь T->C в твоём примере была однозначной и не требовала бы явного задания. (Это был бы, конечно не интерфейс в ООП-смысле, а чистый "контракт", бо интерфейс описывает лишь контракт на экземплярные методы).


K>Зачем какие-то загадочные "интерфейсы для стат.методов" придумывать, если можно просто красиво оформить передачу словаря, т.е. описанную мной технику?


Затем, что многословность. Затем, что лишняя работа, где можно допустить ошибку.

Например, в С++ передачу словарей делают через красивую идеологию traits, которая работает в compile time, через некий traits<T>::something без надобности этот traits подставлять явно. Вернее, дизайн библиотек такой, есть некий traits<>, задаваемый по-умолчанию, но его можно подставить и явно в стиле твоего решения. В итоге, всё работает "изкаробки" для 99% нужд, но у нас остаётся возможность подавать словари явно, как и у тебя, для целей изменения умолчательного поведения.


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


K>Да, совершенно верно, полиморфная рекурсия например. И да, чтоб это использовать нужны более развитые возможности тайплевел-программирования, которых в шарпе нет.


А сама CLR позволит необходимый уровень тайплевел-программирования?


K>Но вообще параметрический полиморфизм, а не шаблоны в дотнете ради раздельной компиляции сделаны. Передача словаря вполне с раздельной компиляцией совместима.


Не понял последнего абзаца.

K>>>Собственно, всякие костыльные воркараунды — единственные способы писать обобщенный код в индус триальных языках

V>>Ну вот мне сходу показалось, что в Swift таких воркараундов должно быть поменьше.

K>Что-то не похоже. Вон https://github.com/maxpow4h/swiftz уже какие-то бедолаги мучаются.


Ты дал ссылку на либу, ОК. Но я не вижу там никаких "костылей". Дважды описать словарь — это костыль. Подать его затем ручками — это костыль. А если просто полезная либа, работающая "изкаробки", в чем костыльность-то? Совсем не надо либы разрабатывать или как? Наоборот, судя по примеру, им вполне удаётся всё делать в нормальном, с т.з. этого языка, синтаксисе. Посмотри сам — словари ручками подавать не надо. )))

Насчет крешей компилятора на Either<A, B>... Мы же о языке, а не о компиляторе. Бету компилятора допилят, ес-но. Насчет С++ template-template аргументов, то популярные компиляторы стали поддерживать эту фичу аж спустя примерно 5 лет после ввода её в сам язык. А непопулярные компиляторы генерили медленный код. ))
Re[19]: Swift
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.06.14 09:09
Оценка: -1
Здравствуйте, vdimas, Вы писали:

V>>>Всё намного проще. Я пока тупо тянул время, бо в эти выходные ни с какой виртуалкой макоси возиться не собирался.


I>>Все почти верно, кроме одной детали — тянуть время ты можешь годами, или выдать "пфф любой студент за два часа, мы не в детсаде"

I>>Вспомнишь сам или ссылкой дать ?

V>Да пофиг. На руках было только описание языка. Согласно его описанию вашу задачку можно решить как тем способом, что настаивал D.Mon, так и тем, что настаивал я. Просто, коль уважаемый мной коллега УТВЕРЖДАЛ, что во встроенных массивах нет итераторов (!!! и я ему ПОВЕРИЛ, т.к. еще не прошелся по базовой либе) я предложил ему решение БЕЗ итераторов вообще.


Это уже третья версия происходящего если считать только твои.
Re[15]: Swift
От: Klapaucius  
Дата: 10.06.14 11:51
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Продемонстрированное тобой решение работает даже в С++, где нет полноценного параметрического полиморфизма. Ууупс?


Ну да. и что? Я вроде не говорил, что оно полноценного полиморфизма требует. Оно просто позволяет совместить полноценный параметрический полиморфизм с ad-hoc.

V>Не получится, если компилятор не видит конечный вызываемый тип для генерика. Т.е. "подхватывать" операторы только компилятором не выйдет. ИМХО, JIT должен "знать в лицо" некий IOperators<> и делать всю эту работу сам.


Но для приведенного мной решения поддержка джита не требуется. JIT ничего не знает про мой CReal, однако инлайнит вызовы потому, что словарь — struct.
Для автоматической подстановки словаря достаточно поддержки компилятора, чтоб он в области видимости искал структуру с имплементацией нужного интерфейса и, допустим, атрибутом TypeClass.

V>Для абстрагирования от конструкторов можно использовать точно такой же трюк как ты показал для операторов


Да нет, я не то имел в виду. Я говорил про конструктор типа вроде List или Dictionary. Чтоб можно было писать <C,T> C<T>

V>По мне обобщенное решение — это которое можно использовать изкаробки. Твоё — нельзя. Оно требует дополнительного явного определения под конкретные типы.


Ну да. "Дополнительное определение под конкретные типы" — это и есть ad-hoc полиморфизм. Посмотрел бы я как вы сможете арифметику без дополнительных определений под конкретные типы реализовать.
Решение же "из каробки" использовать моджно, если положить в коробку словари-имплементации.

V>менно поэтому в базовых либах дотнета показанный тобой трюк не используется, ведь любое решение на нём не будет готово для непосредственного использования.


Почему? В библиотеке есть классы Complex — само число и ComplexNumber — словарь с имплементациями всей арифметики. все можно использовать с любым обобщенным кодом для CNumber.

V>Я бы не говорил так громко, что нет. Классы типов — это и есть аналог подтипирования в ООП, когда речь об абстрактной базе/интерфейсах.


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

V>Фактически идентично в Хаскеле компилятором формируются таблицы для рантайм-полиморфизма, как для виртуальных методов в мейнстримовом ООП.


Нет, это таблицы для компайл-тайм полиморфизма (с редкими исключениями о которых ниже) и в этом тоже принципиальная разница с ООП.

V>Да какая фиг разница, какой механизм мы использовали для задания отношения двух типов???


Большая разница, потому что подтипирование — это грабли.

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


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

V>Если бы ты показал аналог, тебе не надо было бы явно указывать ComplexReal.


Если бы мне было не нужно подставлять словарь вручную — это был бы уже скорее эквивалент.

V>Дважды, потому что operator+ УЖЕ был однажды описан до этого, а не дан свыше.


Ну да, и он переиспользуется, а не реализуется заново. понятно, что то, что в каком-нибудь хаскеле выглядит как foo = bar тут обросло всякими декларациями скобками и ретурнами, ну так на то и индустриальный язык, чтоб жизнь медом не казалась. В принципе, можно и в шарпе сделать менее уродливый dictionary passing, но только он будет тормозить, с ним инлайнер не справится.

V>Ну да. Ты пришпилил к готовому публичному интерфейсу ООП-класса еще один фасад. Поздравляю, чо!


Ну да. И что с того? При написании обобщенного кода "публичный интерфейс ООП-класса" никак не пригодится, но это ж не ФЯ, в ООП обобщенный код скорее исключение, чем правило.

V>Ну так тогда были бы проблемы с синтаксисом на C#. Ты бы не смог писать привычные a+b.


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

V>В С++ тоже именно так и делается.


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

V>Получается, что для обсуждаемого здесь класса задач, т.е. как минимум для записи вычислений через привычные операторы, Swift будет намного удобнее C#.


Да, скорее всего. Но я же не говорил, что эта задача там не решена — она просто решена способом костыльным в другом аспекте. С проблемами для раздельной компиляции, например.

V>Кста! Нечто похожее есть как методы-раширения в C# и Swift. Но, опять же, в дотнете методы-расширения не подхватываются в генериках, а в Swift, насколько я понял — подхватываются.


Ну, с методами-расширениями тут мало общего. Чтоб заключение по Swift сделать — я его еще недостаточно знаю.

V>А смысл???


Например в том, что нет ограничения на волшебные интерфейсы, которые JIT-у известны. Можно определять интерфейс без доступа к коду класса и след. легковесно адаптировать несколько разных библиотек друг к другу. Больше полиморфизма рарешается на этапе компиляции. Мой подход просто быстрее интерфейсов (ну, не для struct, но по обсуждаемой технике можно и class расширять используя struct словари, а значит все будет работать так же быстро и для class).

V>Мне пока приходит в голову лишь тот аргумент, что необходимо иметь несколько независимых наборов определений операторов с одним и тем же синтаксисом, но разной семантикой. Правда, сложно представить пользу от этого на примере complex1+xomplex2.


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

V>Через классы типов + боксирование значений


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

V>диспетчеризацию в рантайм этого бокса по тегу завернутого в нем типа


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

V>Как и в дотнет для value-type, собсно.


Совсем не так. В дотнете JIT-компайл тайм генерируются специализации для value-типов. В хаскеле JIT нет, так что либо все работает как для всех остальных боксированных, а код универсальный для всего, либо если доступны "развертки" — будет специализация и инлайн, worker-wrapper трансформация, чтоб разбоксировать инты. В результате "в цикле" все будет в регистрах. Но это если развертки доступны, т.е. при потере раздельной компиляции на объем этих разверток.

V>Сорри, что опять перешел на механику происходящего,


Ничего плохого в этом нет.

V>но она не сильно-то и отличается.


На самом деле отличается сильно.

V>Такой же точно переход по таблице для выборки адреса ф-ии. С той лишь разницей, что в ООП эта таблица принадлежит конкретному типу, а в Хаскеле — конкретному участку кода, где требуется рантайм-полиморфизм, т.е. типу конкретного выражения, ограниченного классами типов (т.е. заданных через "абстрактные" интерфейсы, с учетом специфики ФП языка).


В том и дело, что в ООП нужно "по таблице переходить" потому, что на какие функции ссылается эта таблица — только в рантайме известно. В случае тайпклассов же функции известны на этапе компиляции, потому их можно заинлайнить (если есть что инлайнить, но в любом случае никакой диспетчеризации уже не будет — только лишняя косвенность и вызовы). В тех случаях, когда подставить словарь в компайл тайм нельзя, (в случае экзистенциальных типов) ссылка на него хранится вместе с данными, как в ООП.
> class Pet a where kill :: a -> String
> data Dog = Dog deriving Show
> data Cat = Cat deriving Show
> instance Pet Dog where kill = const "dead"
> instance Pet Cat where kill = const "c_1|dead> + c_2|alive>"
> map kill [Cat, Cat] -- диспетчеризация времени компиляции
["c_1|dead> + c_2|alive>","c_1|dead> + c_2|alive>"]
> map kill [Dog, Dog] -- диспетчеризация времени компиляции
["dead","dead"]
> data PetBox where Box :: Pet a => a -> PetBox 
> map (\(Box pet) -> kill pet) [Box Dog, Box Cat] -- динамическая диспетчеризация
["dead","c_1|dead> + c_2|alive>"]

Т.е. одно и то же языковое средство работает и как плюсовой шаблон пока может, и как ООП-класс с виртуальными методами, когда без динамической диспетчеризации действительно не обойтись.
И если ООП-класс дает весь оверхед дин. диспетчеризации даже если он невостребован, то класс типов — нет. И для такой оптимизации никаких трассирующих JIT-ов и прочих ухищрений для оптимизации динамики не нужно. Классы типов проще оптимизировать.

V>Опять и снова вопрос — а переопределенные операторы чем не "инстанс"?


Ну а инстансом чего они являются? В принципе, конечно, можно считать, что любой стат. метод это словарь из одной функции для класса типов "сигнатура стат.метода с заменой всех параметров с конкретным типом того класса в котором метод определен на параметры типов".
Может быть это даже приемлемый вариант для добавления классов типов в уже готовый язык.

V>Ну уж какие есть для переопределения. Не так уж и много.


Ну, это ведь не только для операторов должно работать.

V>Чем?


выше, начиная с "Например в том, что нет ограничения на..." и дальше.

V>Диспетчеризация, однако, в том же Хаскель зачастую выполняется в рантайм.


Такое происходит крайне редко, и до появления экзистенциальны типов (это расширение, хотя и старое) вообще не было возможно.

V>От сценариев зависит, так же как и у Хаскеля. Где-то разруливает компилятор, а где-то — на этапе исполнения.


Да нет, параметричность в том и заключается, упрощенно говоря, что проанализировать тип, а значит и диспетчеризовать по нему нельзя. То, что в шарпе с параметром типа можно много чего сделать — это скорее дырявость реализации параметрического полиморфизма в нем.

V>Сам себе противоречишь. Если точные конечные типы можно разрулить на этапе компиляции, то получаем аналог шаблонов С++. Если нет — то у нас рантайм-полиморфизм во всей его кривой красе.


Никакого противоречия тут нет. Параметрический тип с неподставленными в параметры типами на этапе компиляции вполне конечный и полный. Собственно поэтому и полиморфная рекурсия работает. А в плюсошаблонах все параметры для получения "конечного" типа должны быть заполнены.
Понятно, что для запуска программы и при параметрическом полиморфизме параметры нужно подставить (упрощенно говоря, там тоже свои нюансы есть) но библиотечного кода это не касается. Естественно, если все забоксено, то вполне можно генерировать обобщенный код для любых типов. Для оптимизации нужны развертки, но и без них все работает (медленно в случае арифметики, но есть и другие случаи).

V>Я когда-то подробно разбирался с Хаскель. Но не с тем, как на нём решать задачи, а как оно работает "унутре". Всё печально, кароч: при экономной записи исходника — в итоге диспетчеризация в рантайм на каждый мало-мальский чих.


Как-то странно вы смотрели, потому что это не соответствует действительности.

V>Даже в случаях, когда казалось бы, что должен применяться обычный ad-hoc полиморфизм, когда просто идет выбор из "глобальных" с т.з. С++, ф-ий, но вместо ad-hoc — рантайм-механика ПМ по аргументу, а имя ф-ии получается как некое обобщение над всеми наблюдаемыми в точке компиляции типами её аргмента... бррр...


Ничего не понял.

V>В боксе оно хранится и идет "распаковка" этого бокса на той же механике, что и ПМ.


Это даже не та же механика — распаковка это и есть паттерн-матчинг. Ну так не каждый маттерн-матчинг — диспетчеризация.

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


Не понял, о чем речь идет. Вы про то, что каждому параметру типов соответствует параметр функции в промежуточном представлении? Ну так в рантайме этих параметров не будет. или о чем вообще?

V>Обсуждаемой проблемы в Swift нет вообще, как и в С++.


Там обсуждаемая проблема решена костыльным способом.

V>Например?


Например, отсутствие абстрагирования от конструктора типа, о котором выше.

K>>Зачем какие-то загадочные "интерфейсы для стат.методов" придумывать, если можно просто красиво оформить передачу словаря, т.е. описанную мной технику?

V>Затем, что многословность. Затем, что лишняя работа, где можно допустить ошибку.

Ну так если ее нормально оформить — как в хаскеле том же — никакой многословности не будет.
Разумеется, обязательная ручная подстановка — это недостаток моего решения.

V>А сама CLR позволит необходимый уровень тайплевел-программирования?


Тайплевел программирование можно до рантайма и не доводить.

V>Не понял последнего абзаца.


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

V>Ты дал ссылку на либу, ОК. Но я не вижу там никаких "костылей".


Посмотрите, как они там с функторами/монадами мучаются.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[13]: Swift
От: Klapaucius  
Дата: 10.06.14 11:54
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Я бы не сказал, что это типичный код для Си


Мы вроде говорили не про то, какой код обычный, а про то, что плохо в си-синтаксисе, нет?
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[11]: Swift
От: Klapaucius  
Дата: 10.06.14 11:58
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Ради интереса: можно в двух словах, зачем нужно комбинирование комбинаторов и что это вообще такое?

ARK>Нечто типа порождения функций из неких примитивов? Если да, то в чем преимущество перед простым вызовом одной функции из другой?

Комбинирование комбинаторов — это собирание кода из функций с помощью функций, обычно называется "функциональное программирование".
Нужно затем, что это удобный для некоторых (например, для меня) способ декомпозиции.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[14]: Swift
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.06.14 12:07
Оценка:
Здравствуйте, Klapaucius, Вы писали:

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


I>>Я бы не сказал, что это типичный код для Си


K>Мы вроде говорили не про то, какой код обычный, а про то, что плохо в си-синтаксисе, нет?


Если мы отказываемся рассматривать какой код типичный, а какой нет, то в разговоре смысла нет, что очевидно, т.к. в любом языке можно сделать код состоящий из набора закорючек.
Re[12]: Swift
От: AlexRK  
Дата: 10.06.14 14:31
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Комбинирование комбинаторов — это собирание кода из функций с помощью функций, обычно называется "функциональное программирование".


Ясно, я как-то так и представлял.

K>Нужно затем, что это удобный для некоторых (например, для меня) способ декомпозиции.


А есть ли преимущества, помимо личных предпочтений, по сравнению с банальным вызовом функции из другой функции?
Re[13]: Swift
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.06.14 15:06
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Ясно, я как-то так и представлял.


K>>Нужно затем, что это удобный для некоторых (например, для меня) способ декомпозиции.


ARK>А есть ли преимущества, помимо личных предпочтений, по сравнению с банальным вызовом функции из другой функции?


В основном потери перформанса и расход памяти Зато код становится проще, декларативнее и его легче майнтейнить.

Более того — узкие места находить легче
Re[14]: Swift
От: AlexRK  
Дата: 10.06.14 15:17
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Зато код становится проще, декларативнее и его легче майнтейнить.


Про декларативнее — пожалуй. А вот простота разработки, чтения и поддержки, ИМХО, под очень большим вопросом.

I>Более того — узкие места находить легче


За счет чего это происходит?
Re[15]: Swift
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.06.14 16:09
Оценка:
Здравствуйте, AlexRK, Вы писали:

I>>Зато код становится проще, декларативнее и его легче майнтейнить.


ARK>Про декларативнее — пожалуй. А вот простота разработки, чтения и поддержки, ИМХО, под очень большим вопросом.


return items.Select(x => SomeData(x)).Where(x => x.Value != null).GroupBy(x => x.ParenId)


Напиши полный аналог этого кода. Я писал его около 10 секунд, это почти 1 к 1 код из текущей задачи.

Как закончишь, пиши сюда код, время и поговорим про поддержку

I>>Более того — узкие места находить легче


ARK>За счет чего это происходит?


За счет того, что комбинаторы не обычные, а чистые. Можно заменить хоть один, хоть всю цепочку на оптимизированую версию без каких либо проблем.
Re[16]: Swift
От: AlexRK  
Дата: 10.06.14 16:23
Оценка:
Здравствуйте, Ikemefula, Вы писали:

ARK>>Про декларативнее — пожалуй. А вот простота разработки, чтения и поддержки, ИМХО, под очень большим вопросом.


return items.Select(x => SomeData(x)).Where(x => x.Value != null).GroupBy(x => x.ParenId)

I>Напиши полный аналог этого кода. Я писал его около 10 секунд, это почти 1 к 1 код из текущей задачи.

Минутку, а какое отношение это имеет к комбинированию комбинаторов?
Если это комбинирование комбинаторов, то что значит фраза "в отличие от комбинирования комбинаторов, которое если попытаться сделать нормально — целый "полноценный ФЯ" за собой притянут"?
В C# никакого полноценного ФЯ нет.

I>>>Более того — узкие места находить легче

ARK>>За счет чего это происходит?
I>За счет того, что комбинаторы не обычные, а чистые. Можно заменить хоть один, хоть всю цепочку на оптимизированую версию без каких либо проблем.

Ну ведь это применимо и к чистым функциям. В чем профит именно подхода под названием "комбинирование комбинаторов"?
Re[17]: Swift
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.06.14 17:19
Оценка:
Здравствуйте, AlexRK, Вы писали:

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


ARK>>>Про декларативнее — пожалуй. А вот простота разработки, чтения и поддержки, ИМХО, под очень большим вопросом.


ARK>
ARK>return items.Select(x => SomeData(x)).Where(x => x.Value != null).GroupBy(x => x.ParenId)
ARK>

I>>Напиши полный аналог этого кода. Я писал его около 10 секунд, это почти 1 к 1 код из текущей задачи.

ARK>Минутку, а какое отношение это имеет к комбинированию комбинаторов?


Прямое.

ARK>Если это комбинирование комбинаторов, то что значит фраза "в отличие от комбинирования комбинаторов, которое если попытаться сделать нормально — целый "полноценный ФЯ" за собой притянут"?


Карриинг, частичная апликация и тд.

ARK>В C# никакого полноценного ФЯ нет.


Нет, потому комбинаторы слабоватые.

I>>>>Более того — узкие места находить легче

ARK>>>За счет чего это происходит?
I>>За счет того, что комбинаторы не обычные, а чистые. Можно заменить хоть один, хоть всю цепочку на оптимизированую версию без каких либо проблем.

ARK>Ну ведь это применимо и к чистым функциям. В чем профит именно подхода под названием "комбинирование комбинаторов"?


Смотри пример выше. Напиши аналог.
Re[18]: Swift
От: AlexRK  
Дата: 10.06.14 18:02
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Карриинг, частичная апликация и тд.

I>Нет, потому комбинаторы слабоватые.
I>Смотри пример выше. Напиши аналог.

Я не отрицаю пользы LINQ, просто мне казалось, что Klapaucius под "комбинированием комбинаторов" все же имел в виду что-то несколько другое.

Если уточнить, то: в чем практический смысл той сущности (или тех сущностей), которая(ые) требует(ют) для себя "притягивания целого ФЯ"?
Re[13]: Swift
От: Klapaucius  
Дата: 11.06.14 06:31
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>А есть ли преимущества, помимо личных предпочтений, по сравнению с банальным вызовом функции из другой функции?


Тут ложное противопоставление. Функции вызывающие другие функции — это результат. А комбинирование комбинаторов — процесс получения этого результата.
Если рассмотреть реальные альтернативы: собирать функции, вызывающие функции из готовых блоков или не иметь ни готовых блоков, ни средств их объединения — то сразу все будет понятно.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[14]: Swift
От: AlexRK  
Дата: 11.06.14 07:23
Оценка:
Здравствуйте, Klapaucius, Вы писали:

K>Тут ложное противопоставление. Функции вызывающие другие функции — это результат. А комбинирование комбинаторов — процесс получения этого результата.


Т.е. "комбинирование комбинаторов" — это процесс, как "программирование"?
Или конечный артефакт все же существует в виде программного кода?

K>Если рассмотреть реальные альтернативы: собирать функции, вызывающие функции из готовых блоков или не иметь ни готовых блоков, ни средств их объединения — то сразу все будет понятно.


Выделенное следует читать как "при помощи готовых блоков собирать функции, вызывающие другие функции" или как "собирать функции, вызывающие из готовых блоков другие функции"?

Если первое, то чем некий "готовый блок" чем отличается от куска кода в другой форме — например, обычной функции?
Можно ли вот тут сказать, что я собрал функцию из двух готовых блоков:
int combined(int arg)
{
  return func1(func2(arg));
}

?
Re[15]: Swift
От: Klapaucius  
Дата: 11.06.14 07:58
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Т.е. "комбинирование комбинаторов" — это процесс, как "программирование"?

ARK>Или конечный артефакт все же существует в виде программного кода?

Не понял вопроса.

ARK>Выделенное следует читать как "при помощи готовых блоков собирать функции, вызывающие другие функции" или как "собирать функции, вызывающие из готовых блоков другие функции"?


Не уловил принципиальное различие.

ARK>Если первое, то чем некий "готовый блок" чем отличается от куска кода в другой форме — например, обычной функции?


"Готовый блок" в данном случае это функция и есть.

ARK>Можно ли вот тут сказать, что я собрал функцию из двух готовых блоков:

ARK>
ARK>int combined(int arg)
ARK>{
ARK>  return func1(func2(arg));
ARK>}
ARK>

ARK>?

Нет.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[16]: Swift
От: vdimas Россия  
Дата: 11.06.14 08:05
Оценка: -2
Здравствуйте, Klapaucius, Вы писали:

V>>Не получится, если компилятор не видит конечный вызываемый тип для генерика. Т.е. "подхватывать" операторы только компилятором не выйдет. ИМХО, JIT должен "знать в лицо" некий IOperators<> и делать всю эту работу сам.


K>Но для приведенного мной решения поддержка джита не требуется. JIT ничего не знает про мой CReal, однако инлайнит вызовы потому, что словарь — struct.


Так я и не для твоего решения предлагал, а для гипотетического автоматического.

K>Для автоматической подстановки словаря достаточно поддержки компилятора, чтоб он в области видимости искал структуру с имплементацией нужного интерфейса и, допустим, атрибутом TypeClass.


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

V>>Для абстрагирования от конструкторов можно использовать точно такой же трюк как ты показал для операторов

K>Да нет, я не то имел в виду. Я говорил про конструктор типа вроде List или Dictionary. Чтоб можно было писать <C,T> C<T>

А да. В плюсах более менее полноценно поддерживается через template-template, в Swift пока ограничено — можно наследоваться от параметра генерика, т.е. в некоторых сценариях выкрутиться можно. На генериках дотнета принципиально нельзя, ес-но, ведь для такого трюка нужна та самая "текстовая развертка" как ты её обозвал.

V>>По мне обобщенное решение — это которое можно использовать изкаробки. Твоё — нельзя. Оно требует дополнительного явного определения под конкретные типы.


K>Ну да. "Дополнительное определение под конкретные типы" — это и есть ad-hoc полиморфизм. Посмотрел бы я как вы сможете арифметику без дополнительных определений под конкретные типы реализовать.

K>Решение же "из каробки" использовать моджно, если положить в коробку словари-имплементации.

Ладно, конкретно с этим спорить надоело.
1. Я не приемлю повторного определения этого словаря (ведь в первый раз уже определили глобальные операторы).
2. Не приемлю ручное задание соответствия типа и словаря.
3. не приемлю AST-синтаксис арифметических выражений: d.mul(d.add(var1, var2), var3).

Принципиальную возможность определения и использования словаря в дотнете я и не отрицал. Просто эта техника не стала популярной именно из-за перечисленных ограничений. Именно поэтому тебе даже опытные разработчики на дотнете привели необобщенное решение (тело решения было необобщенным), потому что у них уже мозжечок так натренирован. Увы.

V>>менно поэтому в базовых либах дотнета показанный тобой трюк не используется, ведь любое решение на нём не будет готово для непосредственного использования.


K>Почему? В библиотеке есть классы Complex — само число и ComplexNumber — словарь с имплементациями всей арифметики. все можно использовать с любым обобщенным кодом для CNumber.


Что-то я не вижу в базовой библиотеке типа System.Numerics.ComplexNumber. Может, не туда смотрю?


V>>Я бы не говорил так громко, что нет. Классы типов — это и есть аналог подтипирования в ООП, когда речь об абстрактной базе/интерфейсах.

K>Нет, потому что имплементацию интерфейса можно привести к интерфейсу, а тип, для которого имплементация класса типов есть привести к классу типов нельзя. Я именнно об этом.

Я опять и снова НЕ ПОНИМАЮ, что ты так к этому подтипированию прицепился и что тут плохого. В ООП интерфейсы используются как контракт типа. Приведение типа к интерфейсу нужно далеко не всегда, а только лишь в тех случаях, когда требуется рантайм-полиморфизм. В остальных случаях методы могут вызываться явно по их адресу, а не через таблицу диспетчеризации. В Хаскель аналогично — когда компилятор может — вызывает ф-ии, реализующие интерфейс класса, явно. Когда нет — через таблицу диспетчеризации. Приведение к интерфейсу в ООП нужно только для возможности вызывать методы контракта, когда другой возможности нет. Но есть же ООП-языки, которые позволяют т.н. "утиную типизацию", и там приведение к базе не требуется, но через контракты всё еще можно задать требования на интерфейс типа.

V>>Фактически идентично в Хаскеле компилятором формируются таблицы для рантайм-полиморфизма, как для виртуальных методов в мейнстримовом ООП.

K>Нет, это таблицы для компайл-тайм полиморфизма (с редкими исключениями о которых ниже) и в этом тоже принципиальная разница с ООП.

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


V>>Да какая фиг разница, какой механизм мы использовали для задания отношения двух типов???

K>Большая разница, потому что подтипирование — это грабли.

В случае value-type мы имеем один уровень иерархии, так что граблей не много.


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


K>Нет, связи избегать не нужно. Нужно, по возможности, избегать того, что некий тип может быть представлен как набор операций над ним. Это приводит к потере информации о типе, всяким опасным кастам и т.д.


Ага, ну так бы сразу и сказал, что нужно по-возможности избегать парадигмы ООП. )))
Я бы даже не пытался возражать в эту сторону. )))


V>>Если бы ты показал аналог, тебе не надо было бы явно указывать ComplexReal.

K>Если бы мне было не нужно подставлять словарь вручную — это был бы уже скорее эквивалент.

Если бы словарь не надо было организовывать в виде вспомогательного (по-сути, фиктивного) типа, то был бы эквивалент. Если в С++ введут полноценные ограничения на аргументы шаблонов, то эквивалент будет возможно реализовать на С++.


K>При написании обобщенного кода "публичный интерфейс ООП-класса" никак не пригодится, но это ж не ФЯ, в ООП обобщенный код скорее исключение, чем правило.


У нас на С++ только целевые классы обычно не обобщенные, но сами они практически целиком и полностю построены как комбинация обобщенных кубиков низлежащего уровня. Что мы делаем не так?

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


Есть, конечно. Через области видимости. И это можно делать как неймспейсы:
template<template<class, class> class Collection, class Number>
Number roughAvg(const vector<complex> & v)
{
  using namespace RoughMath;

  complex sum = 0;
  for(blah-blah-blah)
    sum += *it;

  return sum / v.size();
}

template<template<class, class> class Collection, class Number>
Number precisionAvg(const Collection<complex> & v)
{
  using namespace PrecisionMath;

  Number sum = 0;
  for(blah-blah-blah)
    sum += *it;

  return sum / v.size();
}


Так и через traits-тип, когда словарь идет как тип-аргумент:
vector<complex> numbers;
...
complex roughResult = avg<rough>(numbers);
complex precisionResult = avg<precision>(numbers);



V>>Получается, что для обсуждаемого здесь класса задач, т.е. как минимум для записи вычислений через привычные операторы, Swift будет намного удобнее C#.


K>Да, скорее всего. Но я же не говорил, что эта задача там не решена — она просто решена способом костыльным в другом аспекте. С проблемами для раздельной компиляции, например.


В чем суть этих проблем?


V>>А смысл???

K>Например в том, что нет ограничения на волшебные интерфейсы, которые JIT-у известны.

Если бы это был первый такой интерфейс — то возражение понятно. Но в дотнете есть неразрывная связь м/у многими типами, компилятором и нижележащей средой исполнения. Так что, этот суп ты уже ничем не испортишь.


K>Можно определять интерфейс без доступа к коду класса и след. легковесно адаптировать несколько разных библиотек друг к другу. Больше полиморфизма рарешается на этапе компиляции. Мой подход просто быстрее интерфейсов (ну, не для struct, но по обсуждаемой технике можно и class расширять используя struct словари, а значит все будет работать так же быстро и для class).


Даже в дотнете это делается через области видимости, через технологию методов-расширений. Сами методы-расширения могут быть генериками.

Просто в дотнете, опять же, полно ограничений в методах-расширениях. Например, те же переопределённые операторы — тю-тю.


V>>Мне пока приходит в голову лишь тот аргумент, что необходимо иметь несколько независимых наборов определений операторов с одним и тем же синтаксисом, но разной семантикой. Правда, сложно представить пользу от этого на примере complex1+xomplex2.



K>Несколько словарей для одного типа — это как раз довольно спорное решение. тут есть трейдофф между когерентностью инстансов и модульностью подхода. В том же хаскеле выбрали первое, а в скале — второе.


Ну вот... а в С++ и Swift можно использовать любой подход по-вкусу. В общем, всё будет зависеть от дизайна конкретной либы.


V>>Через классы типов + боксирование значений

K>Да, так поддерживается. Но довольно странно называть боксированный инт "встроенным",

Для программиста происходящее прозрачно, он по-прежнему оперирует простым инт, поэтому не вижу ничего странного. Просто речь о том, простые типы могут участвовать в сценариях, где их выбор происходит в рантайм. В этом смыслу классы типов ну ОЧЕНЬ похожи на интерфейсы ООП.

K>Никакой диспетчеризации в рантайм не будет. Диспетчеризация в рантайм для сумм, т.е. если конструкторов больше одного. а у забоксенного инта — один конструктор.


В случае Хаскеля мы имеем "автосуммы" допустимых типов выражений прямо в точке вызова некоей ф-ии, описанной в классе типов. Компилятор лепит там рантайм-ПМ прозрачно для программиста.


K>На самом деле отличается сильно.


V>>Такой же точно переход по таблице для выборки адреса ф-ии. С той лишь разницей, что в ООП эта таблица принадлежит конкретному типу, а в Хаскеле — конкретному участку кода, где требуется рантайм-полиморфизм, т.е. типу конкретного выражения, ограниченного классами типов (т.е. заданных через "абстрактные" интерфейсы, с учетом специфики ФП языка).


K>В том и дело, что в ООП нужно "по таблице переходить" потому, что на какие функции ссылается эта таблица — только в рантайме известно.


Известно только если компилятор не видит точный (конечный) тип объекта. Если же видит, то вызывает виртуальные методы напрямую, без таблицы. Именно поэтому я вижу тут аналогию.

K>В случае тайпклассов же функции известны на этапе компиляции, потому их можно заинлайнить (если есть что инлайнить, но в любом случае никакой диспетчеризации уже не будет — только лишняя косвенность и вызовы). В тех случаях, когда подставить словарь в компайл тайм нельзя, (в случае экзистенциальных типов) ссылка на него хранится вместе с данными, как в ООП.

K>
...
K>

Во-во.
Например, там где в Хаскель ЛЮБЫМИ ср-ва языка необходимо было бы выразить последовательность Pet a, там в любом случае поимел бы динамическую диспетчеризаию в стиле ООП. А там, где эта полиморфизм времени исполнения не требуется, там и в ООП прекрасно обходятся без абстрактных классов/интерфейсов.

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


Замечание насчет непосредственного вызова методов вместо виртуальных в ООП я уже делал. Например в С++, если у нас vector<Cat*> — была бы динамическая диспетчеризация, а в случае vector<Cat> — этапа компиляции. В первом случае Cat рассматривался бы как корень некоей иерархии (вдруг там наследник был подан?), а во втором — как точный тип.


K>И если ООП-класс дает весь оверхед дин. диспетчеризации даже если он невостребован, то класс типов — нет.


Это даже в дотнете не так, насколько я знаю.


K>И для такой оптимизации никаких трассирующих JIT-ов и прочих ухищрений для оптимизации динамики не нужно. Классы типов проще оптимизировать.


Это еще на этапе компиляции делается, например, в случае:
var pet = new Cat();
pet.Kill();

Метод Kill будет скомпилирован как обычный вызов, а не виртуальный, в отличие от:
var pet = petFactory.GetSomePet();
pet.Kill();



V>>Опять и снова вопрос — а переопределенные операторы чем не "инстанс"?


K>Ну а инстансом чего они являются? В принципе, конечно, можно считать, что любой стат. метод это словарь из одной функции для класса типов "сигнатура стат.метода с заменой всех параметров с конкретным типом того класса в котором метод определен на параметры типов".

K>Может быть это даже приемлемый вариант для добавления классов типов в уже готовый язык.

Вот из этого я и исходил в своих рассуждениях.


V>>Ну уж какие есть для переопределения. Не так уж и много.

K>Ну, это ведь не только для операторов должно работать.

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


V>>Диспетчеризация, однако, в том же Хаскель зачастую выполняется в рантайм.

K>Такое происходит крайне редко, и до появления экзистенциальны типов (это расширение, хотя и старое) вообще не было возможно.

А как же в случае, когда надо было выразить генератор последовательности Pet a?

V>>Сам себе противоречишь. Если точные конечные типы можно разрулить на этапе компиляции, то получаем аналог шаблонов С++. Если нет — то у нас рантайм-полиморфизм во всей его кривой красе.


K>Никакого противоречия тут нет. Параметрический тип с неподставленными в параметры типами на этапе компиляции вполне конечный и полный.


Но не является уточненным, всё-равно.

K>Собственно поэтому и полиморфная рекурсия работает. А в плюсошаблонах все параметры для получения "конечного" типа должны быть заполнены.


Да.

K>Понятно, что для запуска программы и при параметрическом полиморфизме параметры нужно подставить (упрощенно говоря, там тоже свои нюансы есть) но библиотечного кода это не касается. Естественно, если все забоксено, то вполне можно генерировать обобщенный код для любых типов. Для оптимизации нужны развертки, но и без них все работает (медленно в случае арифметики, но есть и другие случаи).


Да.

V>>В боксе оно хранится и идет "распаковка" этого бокса на той же механике, что и ПМ.

K>Это даже не та же механика — распаковка это и есть паттерн-матчинг. Ну так не каждый маттерн-матчинг — диспетчеризация.

Если в рантайм, то почему не диспетчеризация?


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


K>Не понял, о чем речь идет. Вы про то, что каждому параметру типов соответствует параметр функции в промежуточном представлении? Ну так в рантайме этих параметров не будет. или о чем вообще?


О решении популярного примера на проверку на этапе компиляции длин двух последовательностей на Хаскеле, например.


V>>Обсуждаемой проблемы в Swift нет вообще, как и в С++.

K>Там обсуждаемая проблема решена костыльным способом.

V>>Например?

K>Например, отсутствие абстрагирования от конструктора типа, о котором выше.

Ммм... Не думаю, что для Complex это актуально, даже если у нас Complex<T>.

V>>А сама CLR позволит необходимый уровень тайплевел-программирования?

K>Тайплевел программирование можно до рантайма и не доводить.

Ну тогда не будет CLR библиотек, а только текстовые include их исходников, либо распаршенных вариантов, как в Хаскель. ))

V>>Не понял последнего абзаца.

K>Чего же тут непонятного. Решение с параметрическим полиморфизмом и передачей словарей с раздельной компиляцией совместимо, а "подстановочное" плюсошаблонное — нет.

Почему??? Реализация словаря вполне может быть частью библиотеки.


V>>Ты дал ссылку на либу, ОК. Но я не вижу там никаких "костылей".

K>Посмотрите, как они там с функторами/монадами мучаются.

Видел. В MSVC++ мучались аж до 2005-го года. ))
Потом взлетело.
Re[16]: Swift
От: AlexRK  
Дата: 11.06.14 08:59
Оценка:
Здравствуйте, Klapaucius, Вы писали:

ARK>>Можно ли вот тут сказать, что я собрал функцию из двух готовых блоков:


K>Нет.


Почему?
Не придираюсь, просто хочу понять.
Есть "готовые блоки" func1 и func2. Я их скомбинировал и получил третью функцию.
Re[14]: Swift
От: vdimas Россия  
Дата: 11.06.14 10:41
Оценка:
Здравствуйте, Ikemefula, Вы писали:

V>>Вот тут код: http://www.rsdn.ru/forum/philosophy/5637904.1
Автор: vdimas
Дата: 06.06.14

I>О, круто, в Swift появилась поддержка шаблонов С++. Любопытная идейка.

Да, генерики Swift по-устройству аналогичны шаблонам С++, а не генерикам дотнета. Поэтому вполне корректно.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.