Re[45]: Мифический Haskell
От: VoidEx  
Дата: 05.04.12 10:34
Оценка: +1
Здравствуйте, vdimas, Вы писали:

V>Еще раз, речь шла о динамической типизации в статически-типизириуемом языке. Даже если взять твой пример, например, для JS просто ищется мембер append в словаре-объекте. А вот затем уже происходит динамическая типизация, когда проверяется тип мембера append. Сначала выясняется, что это именно ф-ия, причем нужной арности, т.е. происходит реинтерпретация append-object к append-function[1] и только затем вызов. Вся разница с обсуждаемым в том, что в динамических языках эта механика происходит "унутре само", а в статически компилируемом ты должен описать ее явно, через динамическое приведение типов или ПМ.


Не, разница ещё и в том, что там runtime словарь-объект, а в статическом — compile-time таблица.

Такая же разница, как void foo(int x) и template<int x> void foo();
Re[29]: Мифический Haskell
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 05.04.12 10:51
Оценка:
DM>Стоп-стоп, ты выше ясно сказал, что значения не известны на момент компиляции. Т.е. мы не знаем, что в каком-то массиве будут только инты.

мне, кажется, ты не читаешь то, что написано в треде (об этом говорилось еще 80 постов назад)

http://www.rsdn.ru/forum/decl/4688878.aspx
Автор: DarkGray
Дата: 04.04.12

можно и вызовы dummy2_* развернуть, но для более явного примера, будем считать,
что длина и значения массивов не известны на этапе компиляции,
но тип элементов известен и он одинаковый для всех элементов внутри каждого массива



DM>Дальше, ты тут предполагаешь, что компилятор может угадать и вставить неявное преобразование int -> test вида fun x -> Int x.

DM>Но в любом приличном языке это ошибка, так нельзя. Ведь test мог и так быть определен:
DM>
DM>type test = Int1 of int | Int2 of int | Float of float | String of string
DM>


тогда это будет другой код, и будет требовать другого подхода

DM>В общем виде нет однозначного преобразования int -> test. И даже в нашем частном случае нет оснований считать, что упомянутое выше — то, что нам нужно, а не такое, например:

DM>
fun x -> Float (float_of_int (x*3))


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

DM>Ты отдаешь отчет в том, что для компилятора имена дискриминаторов АлгТД не несут смысла? Что вместо Int of int можно написать Bear of int?


фактически ты сейчас говоришь, что в коде не хватает описания неявных преобразований:
network_int32 -> Int
Int -> network_int32


так добавь их и реши задачу
Re[50]: Мифический Haskell
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 05.04.12 11:01
Оценка:
DG>>слишком упрощенно.
DG>>Например, на текущий момент считается, что невозможно научиться неосознанно точно умножать два десятизначных числа (что является элементарной задачей для калькулятора). Такое умножение можно сделать лишь осознанно в столбик в уме (при сильно развитой кратковременной памяти) или на листке бумаги (если объем кратковременной памяти обычный или меньше).

V_>Научиться этому, наверное, невозможно. Но люди, которые могли это делать, науке известны. Вот, например:


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

я к тому, что от подсознания не стоит ожидать чуда, и не стоит ожидать что оно само сможет правильно решить сложную задачу, в которой требуется большой объем строгих математических вычислений или логических выводов
Re[30]: Мифический Haskell
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 05.04.12 11:03
Оценка: +1
Здравствуйте, DarkGray, Вы писали:

DM>>Стоп-стоп, ты выше ясно сказал, что значения не известны на момент компиляции. Т.е. мы не знаем, что в каком-то массиве будут только инты.

DG>мне, кажется, ты не читаешь то, что написано в треде (об этом говорилось еще 80 постов назад)
DG>можно и вызовы dummy2_* развернуть, но для более явного примера, будем считать,
DG>что длина и значения массивов не известны на этапе компиляции,
DG>но тип элементов известен и он одинаковый для всех элементов внутри каждого массива

Ну да, все правильно. В массиве [|Int 2; String "aa"; Float 4.0|] тип всех элементов одинаковый — test. Хрен его обсчет соптимизируешь. Подобной информации недостаточно для смелых оптимизаций.

DG>сейчас мы говорим о конкретном коде, и о том насколько его можно оптимизировать


Только ты продолжаешь его дописывать и дописывать.

DG>фактически ты сейчас говоришь, что в коде не хватает описания неявных преобразований:

DG>network_int32 -> Int
DG>Int -> network_int32
DG>так добавь их и реши задачу

Ты уже выше приводил нечто похожее на решение в таком случае. Там сумма dummy по массиву интов превращалась в умножение длины массива на константу, не вижу смысла повторять.
Re[44]: Мифический Haskell
От: vdimas Россия  
Дата: 05.04.12 11:05
Оценка:
Здравствуйте, VoidEx, Вы писали:


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


VE>Сложности с тем, что одна и та же программа, но по-разному наложенная на типизацию, в одном случае динамически типизирована, в другом — нет.


Набор слов...

VE>И ты вроде с этим соглашаешься, но при этом отрицаешь, что важно не поведение программы (поведение идентично, никаких реинтрпретаций памяти лишних не происходит), а только то, как поверх положена типизация.


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


VE>>>Возьмём CPS-трансформацию, все АлгТД при этом исчезают. Исчезает ли динамическая типизация?


V>>В твоих примерах — ес-но. А ты не ты сам не увидел?


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


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


VE>При этом в одном случае типизация почему-то динамическая, а в другом — нет.


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


V>>В первом случае ты слил в "бутылочное горлышко" АТД, т.е. потерял информацию о конкретном типе, затем ты "разлил из бутылочного горлышка" обратно, протестировав признак типа. А во втором случае вызвал целевые ф-ии ДО потери информации о конкретном типе.


VE>Только вот код эквивалентен и механически преобразуется один в другой.


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


V>>Аналоги в дотнете, если тебе так будет понятней:


VE>Именно, что не аналоги.


Полные аналоги.

VE>А если v is MyClass? Где передача MyClass onMyClass? HisClass onHisClass? И так для _всех_ типов.

VE>Именно, что это не аналоги. Как говорится, прочувствуй разницу.
VE>Теперь понял?

Нет, можно сформулировать почетче?


V>>Аналог с той разницей, что object — это условно такой АТД, который объединяет всё мн-во типов дотнета, наследников object. Или можно взять какую-нить sealed-иерархию, чтобы ограничить мощность варианта в точности как в примере до {int, string}, но для сути примера это было вовсе не обязательно.


VE>Не просто все, а все возможные и все добавляемые в будущем.


В примере идет работа со всеми другими типами, добавленными в будущем? Можно таки услышать аргументированное возражение на выделенное относительно твоих примеров? Просто любопытно.


V>>Еще вопросы?


Еще.

Ты таки знаешь, что есть sealed в дотнете или нет? А как объявить в С++ тип, от которого нельзя наследоваться? А если да, то к чему эта набишая оскомину (сорри) манера хаскелистов, когда нечем крыть, срываться на один и тот же "последний бастион" — автоматическую проверку множества допустимых значений АлгТД? Я ведь этот трюк знаю уже относительно давно, только поэтому приписал выделенное выше. Характерно, что ты это выделенное перескочил и таки привел стандартный "последний аргумент". Поздравляю!


VE>Конечно. Ты пропустил пример про алгебры, где я убрал ADT вообще.

VE>Любая программа может быть так трансформирована автоматически, ADT при этом исчезают, но программы остаются эквивалентными.

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

В общем, приведенная тобой в качестве возражения техника инлайна мало того, что улыбает сама по себе в кач-ве аргумента обсуждаемому, дык еще работает только там же, где она работает в других языках — где мощность требуемых спекулятивных вычислений не превышает некоего порога. Например для GCC оптимизатором просматривается вложенность всего до 10 уровней... но это уже десятая степень от фиг его знает какого основания (зависит от "ветвистости" кода).


VE>Исчезает ли динамическая типизация?

VE>Внимание, вопрос: исчезает ли она, если код остается прежним, но компилятор внутри проводит такую трансформацию при компиляции?

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


VE>Думай.


Да че думать, проходили уже более десятка лет назад. Ничего нового пока не услышал. Это всё так... объяснение реально происходящего для самих Хаскелистов.
Re[44]: Мифический Haskell
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 05.04.12 11:07
Оценка:
DG>>если все типы известны при генерации кода (новые типы после генерации не подгружаются, или при подгрузке новых типов происходит перегенерация кода), то dynamic_cast — это тоже банальный switch

FR>То это будет не dynamic_cast, а в нем основной смысл в том что он должен работать и на неизвестных во время компиляции типах и

FR>без поиска по ветке наследования не обойтись.

если используется компиляция в виде JIT-а, то оба утверждения верны одновременно:
типы грузятся в runtime-е && все типы известны на момент компиляции.
Для выполнения этого утверждения достаточно знать какой код необходимо перегенерить при последующих подгрузках новых модулей.
Re[45]: Мифический Haskell
От: FR  
Дата: 05.04.12 11:14
Оценка: +2 -1 :)
Здравствуйте, vdimas, Вы писали:

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


Нет это не динамическая типизация. Это динамическая диспетчеризация максимум.


V>Ты сделал сразу две ошибки. Даже если брать твой код, то 1.switch — точно такой же поиск.


Нет в случае switch все возможные пути исполнения _гарантировано_ известны на момент компиляции.

V>2. успех каждой отдельно взятой ветки тоже не гарантирован.


В случае АлгТД гарантирован.

V>А если брать полный аналог на С++, т.е. взять точные типы для сравнения, а не базовые, то для успеха каждой ветки потребуется ровно одно сравнение. Т.е. стоимость будет заведомо идентичная, бо во время dynamic_cast сравниваются адреса vtable, а у АлгТД в Хаскеле сравниваются адреса своей внутренней описательной структуры. Всё 1-к-1-му.


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

V>Далее, ты намекаешь — на контроль типов в Хаскеле? И как это связано с механикой? Это всего-лишь встроенный механизм типобезопасности. В С++ и в дотнете без проблем можно породить одноуровневую sealed-иерархию от некоего базового типа, чтобы получить точно такие же гарантии. На суть происходящего это не повлияет.


Повлияет и кардинально, выбор становится полностью ограниченным, никакие рантайм ошибки кроме Match_failure (если ПМ был неполный)
просто невозможны.

FR>>В результате получаем указатель через который

FR>>можем исполнить код _не известный_ на этапе компиляции (например подгруженная dll).

V>Через указатель код исполнить нельзя, можно через таблицу ф-ий, т.е. через адрес ф-ии. В Хаскеле точно так же можно подать адрес неизвестной заранее ф-ии и исполнить.


В Хаскеле посредством ПМ над АлгТД невозможно исполнить неизвестный код.

FR>>ПМ ничего ни ищет в рантайме, все возможные пути исполнения и код который будет исполнятся известны заранее, он только передает

FR>>управление этим заведомо известным путям исполнения.

V>А почему в С++ не передает заведомо известным путям исполнения? Слишком много предположений, хотя код для сравнения приведен так и не был.


Потому что не может заранее знать все эти пути, они известны только в рантайме. В случае ПМ они известны во время компиляции.

FR>>В случае АлгТД точно также содержимое совершенно достоверно известно до проверки метки. И как в случае union метка, в случае АлгТД

FR>>ПМ только актуализирует какой конкретный из заранее известных вариантов выбрать.

V>Ну так известно заранее, или надо актуализировать? Определись.


Известны заранее все возможные варианты ПМ тупо выбирает один из них, полный аналог сишного switch ничего в рантайме ни
добавить ни убавить, все абсолютно детерминировано.

FR>>В дотнете к сожалению не разбираюсь.


V>Ну хорошо, покажи для Java.


Яву тоже не знаю.


V>Нет, это полная динамика. Но вся динамика сводится к проверке адресов дескрипторов типов, так же как в Хаскеле или С++. 1-в-1.


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

FR>>При полной эмуляции у нас типы Type1, Type2 и т. д. заранее не известны и (псевдо)код будет примерно такой:


V>Упс. Ты уверен, что понимаешь, что есть динамическая типизация?


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

FR>>typetable заполняется в рантайме.


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


DLL может без проблем эскпортировать одну функцию MyInterface *GetInterface(); и линкер ничего не сможет узнать что там
реально внутри. Но dynamic_cast будет работать.

V>На досуге нарисуй цепочку связанных vtable для C++, убедись, в какую сторону идет зависимость (коль повторно говоришь о цепочке наследования). Никогда эти связи не идут от базы к наследникам, т.е. никогда vtable динамически не заполняется, даже при ручной динамической подгрузке DLL.


Не вижу связи с vtable, для dynamic_cast достаточно информации в rtti о наследниках.

Это в С++ она заполняется статически, в питоне во время исполнения.
Но даже в C++ она полностью заполняется только в момент запуска приложения, то есть в рантайме.


V>Ничего не понял. Что значит термин "структурная распаковка"? Чем не понравилось "реинтерпретация памяти"?


Вот в питоне

x, y = (1, 2, 3) это структурная распаковка, то же самое в ML будет ПМ.
Отличие в том что при ПМ типы выведены и известны, при распаковке в динамике просто присваивание.

V>Я повторюсь, что динамическая типизация в статически компиллируемом языке это следующая 2-х тактная операция:

V>1. проверка метки типа.
V>2. реинтерпретация интересующей области памяти согласно метки типа.

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

V>В вырожденном случае предиката только п.1, но не суть.



V>Еще раз, речь шла о динамической типизации в статически-типизириуемом языке. Даже если взять твой пример, например, для JS просто ищется мембер append в словаре-объекте. А вот затем уже происходит динамическая типизация, когда проверяется тип мембера append. Сначала выясняется, что это именно ф-ия, причем нужной арности, т.е. происходит реинтерпретация append-object к append-function[1] и только затем вызов. Вся разница с обсуждаемым в том, что в динамических языках эта механика происходит "унутре само", а в статически компилируемом ты должен описать ее явно, через динамическое приведение типов или ПМ.


Нету в статически-типизириуемом языке никакой динамической типизации.

V>Потому как объект JS это натуральный АлгТД:

V>String s | Number n | Function f | Dictionary d.
V> // JS-Array is Dictionary

Не знаю как в JS, но в питоне или руби объект никак ни аналог АлгТД, так как содержит неизвестное число вариантов подтипов,
и эти подтипы могут меняться и порождаться (в питоне метаклассы и оператор type) в рантайме.

V>И вот внутри этого множества типов работает вся динамическая типизация JS. И происходящее при этом в точности равно происходящему в ПМ на Хаскеле.


В питоне совершено не соответствует.

V>Для Схемы и Лиспа аналогично, только кол-во встроенных типов данных чуть больше, а Dictionary замени на Cons. Кстати, исходников простеньких реализаций Лиспа и Схемы дофига, можно взглянуть на происходящее там и убедиться, что я тебя не обманываю — точно такой же switch по меткам типа объектов, как ты привел пример на С сообщением выше.


Я смотрел, правда давно, там switch только по известным встроенным типам.

FR>>То есть сплошной поиск никак несводимый к switch.


V>Таки сводимый.


Нет число веток в таком "динамическом switch" неизвестно и может меняться по ходу выполнения.
Re[46]: Мифический Haskell
От: vdimas Россия  
Дата: 05.04.12 11:15
Оценка:
Здравствуйте, VoidEx, Вы писали:

VE>Не, разница ещё и в том, что там runtime словарь-объект, а в статическом — compile-time таблица.


Ну так и язык обсуждался динамический, а не как у нас. И да, для того же Лиспа, при компиляции во внутреннее представление, некая ф-ия ищется лишь однажды по имени и лишь однажды происходит динамическая типизация найденного объекта, и лишь однажды проверяется ее арность — это происходит во время разбора исходников. А во время работы кода, при повторных вызовах, уже ничего не ищется, а просто вызывается. Т.е. хотя этот некий p-code построен динамически, вызов затем идет статически. Тоже интересный момент. Поэтому классический Лисп относительно шустрый, пошустрее классического JS.
Re[45]: Мифический Haskell
От: FR  
Дата: 05.04.12 11:25
Оценка:
Здравствуйте, DarkGray, Вы писали:

DG>если используется компиляция в виде JIT-а, то оба утверждения верны одновременно:


JIT же не работает с исходным кодом, он компилирует некий PI-код в котором типизация не совпадает
с исходным.
Re[45]: Мифический Haskell
От: VoidEx  
Дата: 05.04.12 12:27
Оценка:
Здравствуйте, vdimas, Вы писали:

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


Контрпример можно?

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


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


Это не суперкомпиляция, это тривиальное преобразование. Причём его можно производить в обе стороны без смены семантики И поведения.
Если это не так, прошу предоставить контр-пример.

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


Если оптимизация состоится всегда, то это не оптимизация.

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


Правда для общего случая. Разница в том, что общий случай с АлгТД имеет фиксированное число вариантов, в случае обычного ООП общий случай шире.
Ты мне можешь так же доказывать, что построение таблицы на switch — это оптимизация, потому что в общем случае enum — это число, а какое число — мы не знаем. Но у нас не "любое" число, а enum, и мы знаем при компиляции все возможные принимаемые значения. Т.е. эта т.н. "суперкомпиляция" работает всегда. И потому это не оптимизация.
Вот в некотором другом языке, где эти enum можно расширять, добавляя новые значения, это уже будет суперкомпиляцией и оптимизацией.

V>Полные аналоги.


Нет.

VE>>А если v is MyClass? Где передача MyClass onMyClass? HisClass onHisClass? И так для _всех_ типов.

VE>>Именно, что это не аналоги. Как говорится, прочувствуй разницу.
VE>>Теперь понял?

V>Нет, можно сформулировать почетче?


Количество наследников открыто. Если сделать закрытую иерархию, то можно будет сделать такое преобразование. Но для ООП — это частный случай, и потому оптимизация (чем ты и пытаешься аргументировать). Для ADT же это общий случай, работающий всегда.
Как с "любым числом" и enum'ом. Можно, конечно, говорить, что компилятор, который учёл, что у нас всего 3 значения enum'а (red green и blue), провёл суперкомпиляцию, но это не так. Вот если потенциально значение enum'ов бесконечно, но компилятор как-то догадался, что в данном случае их три — то суперкомпиляция. Здесь же ситуация другая.

V>Ты таки знаешь, что есть sealed в дотнете или нет? А как объявить в С++ тип, от которого нельзя наследоваться?


Вот в dotnet — это частный случай. А в Haskell — нет.

Аргументы будут? АлгДТ можно преобразовать в алгебру, которая есть кортеж функций.
Вот пример побольше:

-- data List a = Null | Cons a (List a)
data ListAlgebra a r = ListAlgebra r (a -> r -> r)

-- foldl :: (a -> b -> a) -> a -> [b] -> a
foldList :: (a -> b -> a) -> a -> ListAlgebra b a
foldList f v = ListAlgebra nil cons where
    nil = v
    cons x xs = f xs x

-- l :: List Int
l :: ListAlgebra Int r -> r
-- l = [1, 2, 3]
l (ListAlgebra nil cons) = cons 1 (cons 2 (cons 3 nil))

-- test = foldl (+) 10 l
test = l (foldList (+) 10)

-- data Nat = Zero | Succ Nat
data NatAlgebra r = NatAlgebra r (r -> r)

-- foldNat :: (a -> a) -> a -> Nat -> a
foldNat :: (a -> a) -> a -> NatAlgebra a
foldNat f v = NatAlgebra v f

-- nat :: Int -> Nat
-- просто для удобства, чтоб не писать succ (succ (succ zero))
nat :: Int -> NatAlgebra a -> a
nat 0 (NatAlgebra z s) = z
nat n alg@(NatAlgebra z s) = s $ nat (n - 1) alg

-- replicate :: a -> Nat -> List a
replicateA :: a -> NatAlgebra (ListAlgebra a r -> r)
replicateA v = NatAlgebra z s where
    z (ListAlgebra nil cons) = nil
    s f alg@(ListAlgebra nil cons) = cons v (f alg)

-- ADT
testS = foldl (+) 11 (replicate 5 3)
-- Algebras
testA = (nat 3) (replicateA 5) (foldList (+) 11)


В общем, без какого-либо осмысленного контраргумента дальше обсуждать тему бессымсленно.
Re[45]: Мифический Haskell
От: VoidEx  
Дата: 05.04.12 12:33
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Ты сделал сразу две ошибки. Даже если брать твой код, то 1.switch — точно такой же поиск. 2. успех каждой отдельно взятой ветки тоже не гарантирован. А если брать полный аналог на С++, т.е. взять точные типы для сравнения, а не базовые, то для успеха каждой ветки потребуется ровно одно сравнение. Т.е. стоимость будет заведомо идентичная, бо во время dynamic_cast сравниваются адреса vtable, а у АлгТД в Хаскеле сравниваются адреса своей внутренней описательной структуры. Всё 1-к-1-му.


Да ну неужели? Не позорься.
http://msdn.microsoft.com/en-us/library/cby9kycs(VS.80).aspx
Для dynamic_cast нужен RTTI. Для виртуальных функций — нет.
Re[46]: Мифический Haskell
От: vdimas Россия  
Дата: 05.04.12 12:41
Оценка:
Здравствуйте, FR, Вы писали:

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


FR>Нет это не динамическая типизация. Это динамическая диспетчеризация максимум.


Называй как хочешь, но динамическая типизация в статически-компиллируемом языке — это приведение типов с проверкой, то бишь условное приведение, в отличие от безусловной реинтерпретации памяти. В безусловной реинтерпретации не происходит никаких действий в рантайм, связанных с типизацией. Т.е. никакой динамики.


FR>Нет в случае switch все возможные пути исполнения _гарантировано_ известны на момент компиляции.


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

FR>В случае АлгТД гарантирован.


В случае sealed мн-ва тоже.

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


Не аргумент, т.к. абсолютно любой случай позволяет не использовать dynamic_cast. Пожалуйста — эмулируй работу динамической типизации сам. Например через АлгТД или наподобие COM.


FR>dynamic_cast конечно по разному работает в разных компиляторах, но никак ни сводится к сравнению адресов vtable,

FR>без rtti и содержащейся в ней информации об иерархии наследования он не работает.

Значит ты не в курсе, как хранится rtti и при чем тут vtable для dynamic_cast?


V>>Далее, ты намекаешь — на контроль типов в Хаскеле? И как это связано с механикой? Это всего-лишь встроенный механизм типобезопасности. В С++ и в дотнете без проблем можно породить одноуровневую sealed-иерархию от некоего базового типа, чтобы получить точно такие же гарантии. На суть происходящего это не повлияет.


FR>Повлияет и кардинально, выбор становится полностью ограниченным, никакие рантайм ошибки кроме Match_failure (если ПМ был неполный)

FR>просто невозможны.

Я не увидел пояснения отличий механики при этом. А если я в твой swicth добавлю ветку default:, механика кардинально изменится, что ле?


V>>Через указатель код исполнить нельзя, можно через таблицу ф-ий, т.е. через адрес ф-ии. В Хаскеле точно так же можно подать адрес неизвестной заранее ф-ии и исполнить.


FR>В Хаскеле посредством ПМ над АлгТД невозможно исполнить неизвестный код.


Если в алгТД хранится ф-ия — то можно.



V>>А почему в С++ не передает заведомо известным путям исполнения? Слишком много предположений, хотя код для сравнения приведен так и не был.


FR>Потому что не может заранее знать все эти пути, они известны только в рантайме. В случае ПМ они известны во время компиляции.


Это не ответ. Перечитай вопрос еще раз. Куда и какое управление передается во время самого процесса типизации?


V>>Ну так известно заранее, или надо актуализировать? Определись.

FR>Известны заранее все возможные варианты ПМ тупо выбирает один из них, полный аналог сишного switch ничего в рантайме ни
FR>добавить ни убавить, все абсолютно детерминировано.

Ну так выбирает или детерминировано?
Даже если всего два варианта — уже недетерминировано. Вот я и сравниваю механику приведения недетерминированного типа к детерминированному.


V>>Нет, это полная динамика. Но вся динамика сводится к проверке адресов дескрипторов типов, так же как в Хаскеле или С++. 1-в-1.


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


Это ты какую-то другую динамику имеешь ввиду. Какие еще типы формируются в рантайм для С++?

FR>Я уверен что ты не понимаешь.

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

Это не есть динамическая типизация в статически-компилируемом языке. Это ты о каком-то динамическом языке рассказываешь.


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


FR>DLL может без проблем эскпортировать одну функцию MyInterface *GetInterface(); и линкер ничего не сможет узнать что там

FR>реально внутри. Но dynamic_cast будет работать.

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


V>>На досуге нарисуй цепочку связанных vtable для C++, убедись, в какую сторону идет зависимость (коль повторно говоришь о цепочке наследования). Никогда эти связи не идут от базы к наследникам, т.е. никогда vtable динамически не заполняется, даже при ручной динамической подгрузке DLL.


FR>Не вижу связи с vtable, для dynamic_cast достаточно информации в rtti о наследниках.


Нет никакой информации о наследниках, есть только информация о базе. И сама rtti для типов, могущих быть аргументом dynamic_cast, хранится в vtable по отрицательному смещению. Поэтому идет просто сравнение адресов vtable, и только при неудачном сравнении сравниваются vtable из всех базовых классов рекурсивно (ссылки на которые хранятся в rtti), и т.д. Но если уровень наследования один, то все происходит с примерно такими же затратами, как твой switch. И выход на удачную ветку происходит ровно так же как в ПМ: сравнили адреса vtable, если совпали, то реинтерпретируем область памяти по указателю как значение другого типа.


FR>Это в С++ она заполняется статически, в питоне во время исполнения.

FR>Но даже в C++ она полностью заполняется только в момент запуска приложения, то есть в рантайме.

В момент загрузки объектного модуля загрузчиком ОС. Это и называется статически. (Посмотри на таблицу экспорта, когда экспортируешь класс с виртуальными ф-иями из DLL и включен RTTI). Еще более статической техники просто не существует в природе. Ну кроме embedded софта, где нет никакой рантайм-загрузки приложений, а вся программная начинка — это одна скомпилированная программа по абсолютным адресам.


V>>Ничего не понял. Что значит термин "структурная распаковка"? Чем не понравилось "реинтерпретация памяти"?


FR>Вот в питоне


FR>x, y = (1, 2, 3) это структурная распаковка, то же самое в ML будет ПМ.

FR>Отличие в том что при ПМ типы выведены и известны, при распаковке в динамике просто присваивание.

Т.е. ты в упор отказываешься сравнивать похожие техники у похожих по характеристикам языков? С чем именно тогда споришь?



V>>Я повторюсь, что динамическая типизация в статически компиллируемом языке это следующая 2-х тактная операция:

V>>1. проверка метки типа.
V>>2. реинтерпретация интересующей области памяти согласно метки типа.

FR>Это не динамическая типизация. Придумай другой термин. Этот только все запутывает

FR>и порождает абсолютно бестолковые и неконструктивные споры.

Другой динамической типизации в статически типизируемом языке не существует, увы.
А нет, вру, существует на vtable при вызове виртуального метода — тоже происходит реинтерпретация типа this. И даже происходит коррекция числового адреса this, согласно реинтерпретации и примера здесь: http://www.rsdn.ru/forum/decl/4689256.1.aspx
Автор: vdimas
Дата: 04.04.12



V>>Еще раз, речь шла о динамической типизации в статически-типизириуемом языке. Даже если взять твой пример, например, для JS просто ищется мембер append в словаре-объекте. А вот затем уже происходит динамическая типизация, когда проверяется тип мембера append. Сначала выясняется, что это именно ф-ия, причем нужной арности, т.е. происходит реинтерпретация append-object к append-function[1] и только затем вызов. Вся разница с обсуждаемым в том, что в динамических языках эта механика происходит "унутре само", а в статически компилируемом ты должен описать ее явно, через динамическое приведение типов или ПМ.


FR>Нету в статически-типизириуемом языке никакой динамической типизации.


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


V>>Потому как объект JS это натуральный АлгТД:

V>>String s | Number n | Function f | Dictionary d.
V>> // JS-Array is Dictionary

FR>Не знаю как в JS, но в питоне или руби объект никак ни аналог АлгТД, так как содержит неизвестное число вариантов подтипов,

FR>и эти подтипы могут меняться и порождаться (в питоне метаклассы и оператор type) в рантайме.

Дык, а в Киеве дядька.


V>>И вот внутри этого множества типов работает вся динамическая типизация JS. И происходящее при этом в точности равно происходящему в ПМ на Хаскеле.

FR>В питоне совершено не соответствует.

Очень жаль Питон.


V>>Для Схемы и Лиспа аналогично, только кол-во встроенных типов данных чуть больше, а Dictionary замени на Cons. Кстати, исходников простеньких реализаций Лиспа и Схемы дофига, можно взглянуть на происходящее там и убедиться, что я тебя не обманываю — точно такой же switch по меткам типа объектов, как ты привел пример на С сообщением выше.


FR>Я смотрел, правда давно, там switch только по известным встроенным типам.


А других и нет. Невстроенный — это cons, а удачно прочитанная парсером пользовательская ф-ия — это уже опять встроенный тип "пользовательская ф-ия", который имеет ссылку на сons — на аргументы ф-ии. Вот когда мы подаем на eval динамически построенный список, там опять происходит динамическая проверка, чтобы первый элемент списка был ф-ий.


FR>Нет число веток в таком "динамическом switch" неизвестно и может меняться по ходу выполнения.


В статически-компилируемом языке — не может.
Re[44]: Мифический Haskell
От: vdimas Россия  
Дата: 05.04.12 12:54
Оценка:
Здравствуйте, FR, Вы писали:

DG>>если все типы известны при генерации кода (новые типы после генерации не подгружаются, или при подгрузке новых типов происходит перегенерация кода), то dynamic_cast — это тоже банальный switch


FR>То это будет не dynamic_cast, а в нем основной смысл в том что он должен работать и на неизвестных во время компиляции типах и


Сорри, но аргументами dynamic_cast не может быть неизвестный тип. Оба типа известны: из которого надо преобразовать и в который. Тебя, похоже, смущает, что фактически значением по указателю может быть некий наследник, неизвестный в момент компиляции, я правильно понимаю?

Не пробовал нарисовать, как это работает?


FR>без поиска по ветке наследования не обойтись.


Ну так это ветка идет исключительно к базе, какие проблемы? Всех наследников ведь перебирать не надо. А для случая безопасного одноуровневого sealed-множества наследников — это ровно одно сравнение на вариант, 1-в-1 как в ПМ.
Re[47]: Мифический Haskell
От: VoidEx  
Дата: 05.04.12 12:54
Оценка: -1
Здравствуйте, vdimas, Вы писали:

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


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

struct some // not union!
{
  bool f;
  int x;
  float y;
};

void foo(some const & x)
{
  if (x.f)
    useInt(x.x);
  else
    useFloat(x.y);
}


А что, используем разные типы!

Если вдруг ты захочешь намекнуть, что для чёткости x и y должны были бы лежать в одном месте (как union), то на это я тебе отвечу:

template <class L, class R>
struct HaskellEither // not union!!!
{
  bool which;
  L * l;
  R * r;
};


Опачки! Т.е. если в Haskell Either компилировать не в union с разметкой, а в вышеописанный struct, то внезапно динамическая типизация пропадает? Вот тебе раз!
Тогда давайте считать, что так и есть! А то, что на самом деле union, — всего лишь оптимизация.

По-моему, твоя теория всё более и более противоречивой становится.
Re[47]: Мифический Haskell
От: VoidEx  
Дата: 05.04.12 12:55
Оценка:
Здравствуйте, vdimas, Вы писали:

FR>>В случае АлгТД гарантирован.


V>В случае sealed мн-ва тоже.


Только sealed мн-во — случай частный. Интересно, сколько раз это придётся повторить.
Re[46]: Мифический Haskell
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 05.04.12 12:57
Оценка:
DG>>если используется компиляция в виде JIT-а, то оба утверждения верны одновременно:

FR>JIT же не работает с исходным кодом, он компилирует некий PI-код в котором типизация не совпадает

FR>с исходным.

во-первых:и что из этого утверждения следует?
во-вторых: утверждение неполное (и отражает лишь одну часть реального мира).
есть как языки, где JIT компилирует исходный код, есть где промежуточный,
есть как языки, где в PI-коде типизация совпадает с исходной, есть где не совпадает.
Re[31]: Мифический Haskell
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 05.04.12 13:02
Оценка:
DM>Ты уже выше приводил нечто похожее на решение в таком случае. Там сумма dummy по массиву интов превращалась в умножение длины массива на константу, не вижу смысла повторять.

тогда переходим к вопросу: что требуется от type system и ЯП, чтобы ЯП такое решение мог построить самостоятельно?
Re[46]: Мифический Haskell
От: vdimas Россия  
Дата: 05.04.12 13:05
Оценка:
Здравствуйте, VoidEx, Вы писали:

V>>Ты сделал сразу две ошибки. Даже если брать твой код, то 1.switch — точно такой же поиск. 2. успех каждой отдельно взятой ветки тоже не гарантирован. А если брать полный аналог на С++, т.е. взять точные типы для сравнения, а не базовые, то для успеха каждой ветки потребуется ровно одно сравнение. Т.е. стоимость будет заведомо идентичная, бо во время dynamic_cast сравниваются адреса vtable, а у АлгТД в Хаскеле сравниваются адреса своей внутренней описательной структуры. Всё 1-к-1-му.


VE>Да ну неужели? Не позорься.


Начинается...
Сам торопыжка.

VE>http://msdn.microsoft.com/en-us/library/cby9kycs(VS.80).aspx

VE>Для dynamic_cast нужен RTTI. Для виртуальных функций — нет.

Хе. Упоминался как известный факт, что для работы RTTI нужна таблица виртуальных функций. Похоже, ты этого не знал, я прав? И даже не обратил внимание, что по твоей же ссылке во всех примерах вставлена фиктивная виртуальная ф-ия, не участвующая в примере? А в том примере, где нет фиктивной ф-ии, там никакого dynamic_cast нет, это демонстрация в каком случае dynamic_cast заменяется на static_сast, когда наследника приводим к базе.

Внимательнее надо быть.


================
Коллега, вот объясни, с чем же ты спорил тогда, если не знал, как работает dynamic_cast? Чем же ты собирался аргументировать свой протест, что в Хаскеле происходит не то же самое, что в других языках при динамической типизации?

А в курсе как работает динамическое приведение типов в дотнете?
Re[47]: Мифический Haskell
От: FR  
Дата: 05.04.12 13:18
Оценка:
Здравствуйте, vdimas, Вы писали:

FR>>Нет это не динамическая типизация. Это динамическая диспетчеризация максимум.


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


В общем спасибо за беседу, но дальше продолжать не вижу смысла.
Re[48]: Мифический Haskell
От: vdimas Россия  
Дата: 05.04.12 13:20
Оценка:
Здравствуйте, VoidEx, Вы писали:


VE>Опачки! Т.е. если в Haskell Either компилировать не в union с разметкой, а в вышеописанный struct, то внезапно динамическая типизация пропадает? Вот тебе раз!

VE>Тогда давайте считать, что так и есть!

Легко, ведь действительно никакой динамической типизации делать не надо. Мы можем одновременно пользоваться как L * l, так и R * r; Вот только называть такую структуру Either уже некамильфо. Но копаешь в правильном направлении, еще немного и докопаем.

VE>А то, что на самом деле union, — всего лишь оптимизация.


Вот так с плеча "все лишь"? Ведь это еще изменение семантики, бо одновременно пользоваться l и r можно будет лишь с целью хакнуть типы L и R.


VE>По-моему, твоя теория всё более и более противоречивой становится.


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