Здравствуйте, VoidEx, Вы писали:
VE>Только sealed мн-во — случай частный. Интересно, сколько раз это придётся повторить.
Наверно, ровно столько раз, сколько будет упомянута набившая оскомину "встроенная безопасность" АлгТД Хаскеля.
Ибо, где такая безопасность нужна — делаем такое же по характеристикам мн-во типов. Тем более, что в рантайме эта особенность ничего не стоит, вернее наоборот — позволяет делать агрессивную оптимизацию.
V>>Называй как хочешь, но динамическая типизация в статически-компиллируемом языке — это приведение типов с проверкой, то бишь условное приведение, в отличие от безусловной реинтерпретации памяти. В безусловной реинтерпретации не происходит никаких действий в рантайм, связанных с типизацией. Т.е. никакой динамики.
FR>В общем спасибо за беседу, но дальше продолжать не вижу смысла. FR>
Жаль, я бы с удовольствием обсудил бы граф обхода RTTI во время dynamic_cast, мне, признаюсь, очень хотелось показать, почему для одноуровневого наследования (скажем, при реализации АлгТД на подтипировании в С++) будет ровно одна проверка на вариант, как в ПМ. Уверен, тебе было бы интересно.
DM> Этот отображение — внутренний вопрос конкретного компилятора или интерпретатора. Разные компиляторы/интепретаторы одного и того же языка могут представлять значения одного и того же типа этого языка в памяти по-разному. Например, тип значение "hello" типа String в языке Руби представлено в памяти по-разному в интепретаторах MRI 1.8, IronRuby и JRuby. Другой пример — значение 42 типа int в языке Окамл представлено в памяти по-разному при компиляции в x86 и x64. Но систему типов это не затрагивает.
если вот это перевести на математику, и отбросить словоблудие, то здесь написано, что:
произвольный код на OCaml(Ruby, C и т.д.) прежде чем быть выполнен — должен все типы конкретизировать способом хранения их в памяти.
или другими словами: всякая функция вида:
int F(int){..}
на самом деле обозначает параметрическую функцию вида:
DM> String в языке Руби представлено в памяти по-разному в интепретаторах MRI 1.8, IronRuby и JRuby
значит можно утверждать, что тип String в Руби на самом деле является параметрическим типом String<TMemoryMapping>, который конкретизируется как:
String<MRI_18.String_Memory_Mapping>, String<IronRuby.String_Memory_Mapping>, String<JRuby.String_Memory_Mapping> в зависимости от интерпретатора
DM> пример — значение 42 типа int в языке Окамл представлено в памяти по-разному при компиляции в x86 и x64
значит тип int в OCaml является параметрическим типом int<TMemoryMapping>, который конкретизируется при компиляции в x86/x64, как: int<x86.int_Memory_Mapping> или int<x64.int_Memory_Mapping>
ps
.net-ный тип Int32 является параметрическим типом Integer<signed, size:4, TBigLittleEndian>, который параметризуется TBigLittleEndian:BigEndian или TBigLittleEndian:LittleEndian в зависимости от процессора.
тип char в c/c++ является параметрическим типом Integer<Signed/Unsigned, size:1/2, BigEndian/LittleEndian> в зависимости от компилятора и его настроек (хотя, конечно, для C/C++ можно найти и экзотические варианты параметризации типа char, например, для экзотических архитектур, где в байте не 8 бит, или где в одном бите хранится 3 значения, а не два)
Здравствуйте, vdimas, Вы писали:
V>Хе. Упоминался как известный факт, что для работы RTTI нужна таблица виртуальных функций. Похоже, ты этого не знал, я прав? И даже не обратил внимание, что по твоей же ссылке во всех примерах вставлена фиктивная виртуальная ф-ия, не участвующая в примере? А в том примере, где нет фиктивной ф-ии, там никакого dynamic_cast нет, это демонстрация в каком случае dynamic_cast заменяется на static_сast, когда наследника приводим к базе.
V>Внимательнее надо быть.
Ты никогда не читаешь то, на что отвечаешь? Я где-то написал, что для RTTI не нужна таблица? Где?
Здравствуйте, vdimas, Вы писали:
VE>>Опачки! Т.е. если в Haskell Either компилировать не в union с разметкой, а в вышеописанный struct, то внезапно динамическая типизация пропадает? Вот тебе раз! VE>>Тогда давайте считать, что так и есть!
V>Легко, ведь действительно никакой динамической типизации делать не надо. Мы можем одновременно пользоваться как L * l, так и R * r; Вот только называть такую структуру Either уже некамильфо. Но копаешь в правильном направлении, еще немного и докопаем.
А мы и так можем. Просто один из них всегда Null, что гарантирует конструктор типа. А изменить мы это сами не можем, данные-то read-only.
V>Та хде? V>Я пока вижу обратное — ты все больше и больше выясняешь моментов, которыми раньше, скажем так, не интересовался. Очень полезная для тебя дискуссия. Только давай исключим нервозность из этого процесса.
Хуже другое, ты для себя так ничего и не выяснил. Вернёмся таки к автоматическому избавлению от АлгТД. Будет контрпример или ты признаёшь, что это может быть произведено автоматически и тогда отличия между теми примерами, что я приводил, нет. Т.е. if-else в Си — тоже динамическая типизация (по твоей терминологии)?
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, VoidEx, Вы писали:
VE>>Только sealed мн-во — случай частный. Интересно, сколько раз это придётся повторить.
V>Наверно, ровно столько раз, сколько будет упомянута набившая оскомину "встроенная безопасность" АлгТД Хаскеля. V>Ибо, где такая безопасность нужна — делаем такое же по характеристикам мн-во типов. Тем более, что в рантайме эта особенность ничего не стоит, вернее наоборот — позволяет делать агрессивную оптимизацию.
А то получается, что разницы между всеми тремя примерами нет, но одно ты зовёшь динамической типизацией, а другое — нет. Самое прекрасное, что там одинаковое количество проверок, но тебя это не смущает.
DM>Итак, попробую строго сформулировать своими словами. Основной пререквизит для понимания материала — теория множеств, буду исходить из того, что понятие множества и основные операции с ними читателю известны.
то, что ты написал можно назвать математической подложкой, но не определениями.
определение — должно включать в себя возможность построения предиката, который принимает произвольную часть мира и возвращает true, если произвольная-часть-мира подходит под определение, и false если не подходит.
утверждение, что цвет есть кортеж(R, G, B) — не является определением цвета, а является лишь способом задать мат. модель для цвета.
утверждение "syntactic framework — это пара множеств (B, R)", также не является определением того, чем является syntactic framework, а является одной из попыток представить syntactic framework в виде теоретико-множественной модели.
и то, и другое не является определениями потому что из этих утверждений нельзя построить предикат произвольная-часть-мира -> bool.
утверждение "цвет есть кортеж (R, G, B)" ничего не говорит о том, является ли модель CMYK цветом или нет.
утверждение "syntactic framework — это пара множеств (B, R)" ничего не говорит о том, является ли тройка множеств(Термы, Комбинаторы-Термов, Предикаты-Описывающие-Исключения) syntactic framework-ом или не является.
Здравствуйте, VoidEx, Вы писали:
V>>Легко, ведь действительно никакой динамической типизации делать не надо. Мы можем одновременно пользоваться как L * l, так и R * r; Вот только называть такую структуру Either уже некамильфо. Но копаешь в правильном направлении, еще немного и докопаем.
VE>А мы и так можем. Просто один из них всегда Null, что гарантирует конструктор типа. А изменить мы это сами не можем, данные-то read-only.
Тогда, увы, рантайм проверку на обязательно null придется делать. В этом случае матч по признаку типа выродится в матч по not null. И тогда распаковка немного усложниться, т.к. распаковка будет заключаться не только в простой реинтерпретации первоначального указателя, как это было бы для случая union, но и потребуется дополнительное смещение адреса, уникальное для каждого хранимого варианта.
VE>Хуже другое, ты для себя так ничего и не выяснил. Вернёмся таки к автоматическому избавлению от АлгТД. Будет контрпример или ты признаёшь, что это может быть произведено автоматически и тогда отличия между теми примерами, что я приводил, нет. Т.е. if-else в Си — тоже динамическая типизация (по твоей терминологии)?
Я полностью пояснил свою позицию в той же ветке. Если ты уже там ответил — дойдут руки, отвечу и я.
Здравствуйте, DarkGray, Вы писали:
DG>то, что ты написал можно назвать математической подложкой, но не определениями.
Дайте своё.
DG>определение — должно включать в себя возможность построения предиката, который принимает произвольную часть мира и возвращает true, если произвольная-часть-мира подходит под определение, и false если не подходит.
Определение — это введение понятия. "Будем называть то-то вот таким словом". Поэтому если ваш syntactic framework не подходит под определение D.Mon. тем хуже для вашего syntactic framework. Его нельзя использовать в рассуждениях или давайте ему определение сами.
Вы попросили дать определение, вам его дали. Ведь вы же это сделали, чтобы выработать общие термины? Аппелировать к тому, что это не определение — убивать дискуссию в зародыше.
DG>и то, и другое не является определениями потому что из этих утверждений нельзя построить предикат произвольная-часть-мира -> bool.
"Произвольная часть мира" — это что такое? Речь вроде о математике.
DG>утверждение "syntactic framework — это пара множеств (B, R)" ничего не говорит о том, является ли тройка множеств(Термы, Комбинаторы-Термов, Предикаты-Описывающие-Исключения) syntactic framework-ом или не является.
Покажите эквивалентность этих определений и будет говорить.
Здравствуйте, vdimas, Вы писали:
V>Тогда, увы, рантайм проверку на обязательно null придется делать. В этом случае матч по признаку типа выродится в матч по not null. И тогда распаковка немного усложниться, т.к. распаковка будет заключаться не только в простой реинтерпретации первоначального указателя, как это было бы для случая union, но и потребуется дополнительное смещение адреса, уникальное для каждого хранимого варианта.
Так я не понял, в том Either — динамическая типизация?
А тогда в примере выше с int x и float y получается тоже?
Здравствуйте, vdimas, Вы писали:
VE>>Хуже другое, ты для себя так ничего и не выяснил. Вернёмся таки к автоматическому избавлению от АлгТД. Будет контрпример или ты признаёшь, что это может быть произведено автоматически и тогда отличия между теми примерами, что я приводил, нет. Т.е. if-else в Си — тоже динамическая типизация (по твоей терминологии)?
V>Я полностью пояснил свою позицию в той же ветке. Если ты уже там ответил — дойдут руки, отвечу и я.
Ты утвеждал, что это оптимизация, и в общем случае не работает. Я уже ответил, что это работает всегда.
Здравствуйте, VoidEx, Вы писали:
V>>Я полностью пояснил свою позицию в той же ветке. Если ты уже там ответил — дойдут руки, отвечу и я.
VE>Ты утвеждал, что это оптимизация, и в общем случае не работает. Я уже ответил, что это работает всегда.
Чтобы ты не стал отвечать в духе "в C# есть sealed", дополню. Вот когда там только sealed и будет, и будет гарантия возможности такой трансформации для общего случая, тогда и обсудим. А пока это сродни оптимизации динамического языка, который иногда может вывести, что функцию зовут только с числами, и потому оптимизирует. Это не статика.
Статика позволяет убрать лишний if гарантированно, а не в частных случаях.
Здравствуйте, DarkGray, Вы писали:
DM>> Этот отображение — внутренний вопрос конкретного компилятора или интерпретатора. Разные компиляторы/интепретаторы одного и того же языка могут представлять значения одного и того же типа этого языка в памяти по-разному. Например, тип значение "hello" типа String в языке Руби представлено в памяти по-разному в интепретаторах MRI 1.8, IronRuby и JRuby. Другой пример — значение 42 типа int в языке Окамл представлено в памяти по-разному при компиляции в x86 и x64. Но систему типов это не затрагивает.
DG>значит можно утверждать, что тип String в Руби на самом деле является параметрическим типом String<TMemoryMapping>, который конкретизируется как: DG>String<MRI_18.String_Memory_Mapping>, String<IronRuby.String_Memory_Mapping>, String<JRuby.String_Memory_Mapping> в зависимости от интерпретатора
Утверждать можно сколько угодно, толку то. Что это изменит и что хорошего даст? Пока что эти утверждения лишь вносят путаницу (разные способы параметризации типов) и противоречат спецификациям языков. Не первый раз ты уже смешиваешь систему типов языка и подробности реализации компиляторов/рантаймов.
Здравствуйте, DarkGray, Вы писали:
DG>то, что ты написал можно назвать математической подложкой, но не определениями.
Еще можно горшком назвать. И единорогом тоже можно.
DG>определение — должно включать в себя возможность построения предиката, который принимает произвольную часть мира и возвращает true, если произвольная-часть-мира подходит под определение, и false если не подходит.
Опять фантазируешь. Дай такое определение предиката и мира для начала тогда. А потом определение завершающейся программы.
Здравствуйте, DarkGray, Вы писали:
DG>и то, и другое не является определениями потому что из этих утверждений нельзя построить предикат произвольная-часть-мира -> bool.
Так и быть, вот тебе такой предикат: если некоторая часть мира подходит под мое определение системы типов (т.е. представляет из себя пару... и далее по тексту), то true, иначе false.
Здравствуйте, VoidEx, Вы писали:
V>>Хе. Упоминался как известный факт, что для работы RTTI нужна таблица виртуальных функций. Похоже, ты этого не знал, я прав? И даже не обратил внимание, что по твоей же ссылке во всех примерах вставлена фиктивная виртуальная ф-ия, не участвующая в примере? А в том примере, где нет фиктивной ф-ии, там никакого dynamic_cast нет, это демонстрация в каком случае dynamic_cast заменяется на static_сast, когда наследника приводим к базе.
V>>Внимательнее надо быть.
VE>Ты никогда не читаешь то, на что отвечаешь? Я где-то написал, что для RTTI не нужна таблица? Где?
Ну так ты возразил насчет моего утверждения, что нужна и что именно её сравнения достаточно. Ты даже употребил усиление "не позорься". А теперь вроде как классически юлишь.
Здравствуйте, VoidEx, Вы писали:
V>>Тогда, увы, рантайм проверку на обязательно null придется делать. В этом случае матч по признаку типа выродится в матч по not null. И тогда распаковка немного усложниться, т.к. распаковка будет заключаться не только в простой реинтерпретации первоначального указателя, как это было бы для случая union, но и потребуется дополнительное смещение адреса, уникальное для каждого хранимого варианта.
VE>Так я не понял, в том Either — динамическая типизация? VE>А тогда в примере выше с int x и float y получается тоже?
VE>В чём разница?
Очевидно в том, что при статической типизации никакие проверки в рантайм делать не надо.
В этих твоих мыслительных экспериментах самое примечательное то, что семантически сохраняя поведение программы, ты реализуешь ее то на встроенных проверках аппарата типизации, предоставляемых языком, то выносишь такие проверки из аппарата типизации в пользовательский код, эмулируя похожую механику типизации вручную.
Я же говорю — в правильном направлении копаешь. Еще немного и поймешь, как все работает. Нет в динамической типизации никакой особой магии. В рантайме — это всегда сравнение значений.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, VoidEx, Вы писали:
V>>>Тогда, увы, рантайм проверку на обязательно null придется делать. В этом случае матч по признаку типа выродится в матч по not null. И тогда распаковка немного усложниться, т.к. распаковка будет заключаться не только в простой реинтерпретации первоначального указателя, как это было бы для случая union, но и потребуется дополнительное смещение адреса, уникальное для каждого хранимого варианта.
VE>>Так я не понял, в том Either — динамическая типизация? VE>>А тогда в примере выше с int x и float y получается тоже?
VE>>В чём разница?
V>Очевидно в том, что при статической типизации никакие проверки в рантайм делать не надо.
Ты не понял. У нас просто код:
if (x.f)
fooInt(x.a);
else
fooFloat(x.b);
Это не проверка типов, просто алгоритм ветвится в зависимости от того, какой выставлен флаг. Почему это не динамическая типизация? Алгоритм работает далее с разными типами данных, делает проверку, чтобы выбрать ветвь.
V>В этих твоих мыслительных экспериментах самое примечательное то, что семантически сохраняя поведение программы, ты реализуешь ее то на встроенных проверках аппарата типизации, предоставляемых языком, то выносишь такие проверки из аппарата типизации в пользовательский код, эмулируя похожую механику типизации вручную.
V>Я же говорю — в правильном направлении копаешь. Еще немного и поймешь, как все работает. Нет в динамической типизации никакой особой магии. В рантайме — это всегда сравнение значений.
Я не копаю, я пытаюсь тебе объяснить, но всё бестолку. Давай от АлгТД не увиливай. Я тебе ещё пример нарисую тогда. Более жизненный, но уверенности, что до тебя дойдёт, уже нет.
-- loadConfig :: IO (Maybe ConnectionData)
cdata <- loadConfig
case cdata of
Just cdata' -> do-- tryReceive :: IO (Either Int SomeData)
sdata <- tryReceive cdata'
case sdata of
Right (SomeData bytes value) -> do
putStrLn $ "received " ++ show bytes ++ " bytes"
process value
Left errorCode -> putStrLn $ "error " ++ show errorCode
Nothing -> putStrLn "not loaded"
Что автоматически трансформируемо в:
-- loadConfig :: (ConnectionData -> IO r) -> IO r -> IO r
loadConfig onLoad onFail where
onLoad cdata = tryReceive onData onError where-- tryReceive :: (SomeData -> IO r) -> (Int -> IO r) -> IO r
onData (SomeData bytes value) -> do
putStrLn $ "received " ++ show bytes ++ " bytes"
process value
onError errorCode = putStrLn $ "error " ++ show errorCode
onFail = putStrLn "not loaded"
Здравствуйте, VoidEx, Вы писали:
V>>Дело в том, что в момент такой транфсформации работает техника суперкомпиляции, но на этом этапе никаких типов уже нет, потому что это уже инлайнинг, распространение констант и т.д., а не тайплевел-вычисление, т.е. это обычные спекулятивные вычисления, то бишь эмуляция механики, происходящей в райнтайм. А метки типов — это уже такие же константы на этом этапе. И да, для дотнета эта техника так же может работать, т.к. там тоже есть инлайнинг.
VE>Это не суперкомпиляция, это тривиальное преобразование. Причём его можно производить в обе стороны без смены семантики И поведения. VE>Если это не так, прошу предоставить контр-пример.
Хорошо. Пример очень простой. Берем некое AST, которое сделали на АлгТД. Берем твои рассуждения: компилятор "видит" как это дерево строится, затем видит, как вызывается некая ф-ия обхода дерева, где мы ветвимся на технике ПМ. Компилятор может провести такое преобразование, где вместо нетипизированного "мешка" под названием АлгТД будет во время построения дерева сохранять в узлах замыкания, которые будут захватывать типизированные значения и содержать в себе необходимые процедуры обработки, перенесенные из веток ПМ исходного кода, т.е. работающего уже с уточненными типами узлов.
Я до сюда правильно излагаю?
Итого, одно дерево, одна операция, преобразование туда-обратно идентичное.
Теперь представим, что у нас по этому дереву будет сотня независимых операций обработки, но выбор лишь из одной и это выбор зависит от данных в рантайм. Причем, выбор этот пусть по неким причинам происходит уже ПОСЛЕ построения дерева.
Теперь компилятор должен будет сохранять в узлах дерева не одно замыкание, а сотню. Дадим этому варианту реализации номер №1. По мне — это очень плохой вариант, т.к. слишком много памяти нужно под сотни замыканий, хотя вызвано будет всегда лишь одно из них. Т.е. мало того что под хранения сотен адресов ф-ий в каждом узле нужна будет лишняя память, дык еще в каждом из замыканий будет продублирован захваченный контекст (данные). В итоге, получим кривую пародию на ООП. Кривую, потому что в ООП независимо от кол-ва ф-ий в vtable нам нужен всего один указатель на нее, и сам объект "замыкает" для ф-ий из vtable данные лишь в одном экземпляре. Т.е. сэкономив на проверках, мы значительно потеряли в памяти, т.е. оптимизации как таковой нет.
Давай попробуем вариант №2. Пусть это будет по-прежнему одно замыкание и одна копия данных узла, но мы внутри должны будем протянуть метку текущей операции (пусть будет некий индекс), затем в каждом узле дополнительно разветвиться по этой метке, выбирая алгоритм согласно некоторого индекса. Если компилятор достаточно умный, то это обойдется нам в +2 лишних уровня косвенности и двойную диспетчеризацию (ООП-визитор). Если недостаточно умный, то будет аналог switch на входе каждой процедуры. Но самое примечательное, что убежав от рантайм проверок в одном месте, мы их приобрели в другом, это проверка ТИПА операции, либо дополнительная двойная диспетчерезация на каждом шаге (обе техники взаимозаменяемы, кстате). Поэтому в вариант №2, сэкономив память, мы опять не сэкономили на рантайм-проверках. Опять нет оптимизации.
ЧТД.
Заметь, мы всё еще рассматриваем ситуацию, когда компилятор видит программу целиком, т.е. когда он видит все входы и выходы. Этот сценарий я и назвал случаем "наивной оптимизации". Дело в том, что для такой программы любой вменяемый оптимизирующий компилятор способен нивелировать большую часть излишних динамических проверок. По крайней мере для С++ в таких "замкнутых" программах я наблюдал выкидывание компилятором до половины кода из рантайм. Для каких-нить экспериментов приходилось вносить побочные эффекты, чтобы компилятор не особо расходился в своем порыве.
А теперь берем ситуацию, когда у нас происходит динамическая загрузка некоего плагина. Т.е. при компиляции этого плагина мы не видели ни как было построено дерево, ни какие еще ф-ии требуют его обхода. Что должен делать компилятор? Вот тут твоя техника НЕ работает.
==============
А вообще, утверждение у тебя абсолютно правильно. Забудь про подробность преобразований конкретно АлгТД. Твоё утверждение сводится к тому, что любую программу МОЖНО переписать так, чтобы избежать динамической типизации, предоставляемой средой/языком.
Конечно можно! Тут два основных способа: это LSP, т.е. вариант №1 в начале поста, т.е. гомоморфная иерархия объектов с фиксированным набором операций, либо же ЭМУЛЯЦИЯ динамической типизации БЕЗ таковой. Как примеры: вариант №2 если делать его вручную, реализация COM или тот твой пример, где ты кодируешь информацию о текущем типе Either путем инициализации null у второго элемента пары. Т.е. это прямая эмуляция другой системы типов и динамических преобразований в ней через инструментарий имеющейся. Помнишь, я еще несколько постов назад пытался предостеречь тебя от рассуждений в эту область, т.к. она не доказывает ничего ни для одной из сторон, коль рассматривалась конкретная имеющаяся механика? Не доказывает, потому что одна и та же семантика может быть реализована кучей способов, как с привлечением неких св-в аппарата типов, так и без, через её эмуляцию/дублирование. Но тебя туда тянет по-прежнему.
В общем, если по мне, то обсуждать давно нечего. Не думал, что таких подробный намеков, как я уже делал неоднократно, недостаточно. Пришлось объяснять известные вещи заново, а именно: LSP хорош только там, где кол-во операций заведомо известно, а все зависимости однонаправленные. Поэтому рамки применения LSP не так чтоы очень широки — в плагинной архитектуре и в прочих компонентных моделях LSP не работает, в таких архитектурах требуется именно что динамическая типизация, предоставляемая средой/языком, либо непосредственная эмуляция этой типизации, примерно как в COM или твоем самописном Either.
V>>Потому что если оптимизация не состоялась по каким-либо причинам (нетривиальная зависимость от данных, например), то в одном случае приходится делать это в рантайм, а в другом — не приходится. VE>Если оптимизация состоится всегда, то это не оптимизация.
Да не всегда. Это заблуждение, т.к. ты пока рассматривал замкнутую систему типов. В замкнутой системе даже над дотнетным object можно было производить такие же преобразования, без всяких твоих "частных случаев" навроде специального sealed, т.к. эти sealed как раз нужны для незамкнутой системы. В замкнутой системе, при обеспечении ссылочной прозрачности, даже аннотации типов теряют всякую актуальность, т.к. всё можно вывести из контекста. Но это в каком-то идеальном мире, а не в реальном.
VE>Правда для общего случая. Разница в том, что общий случай с АлгТД имеет фиксированное число вариантов, в случае обычного ООП общий случай шире.
Нет, он непросто шире, он ОТКРЫТ, этот общий случай. Просто был бы шире — это фигня и сводится к варианту №1 или №2 из показанного в начале поста.
VE>Ты мне можешь так же доказывать, что построение таблицы на switch — это оптимизация, потому что в общем случае enum — это число, а какое число — мы не знаем. Но у нас не "любое" число, а enum, и мы знаем при компиляции все возможные принимаемые значения. Т.е. эта т.н. "суперкомпиляция" работает всегда. И потому это не оптимизация.
Не, ты всерьез считаешь, что если в switch из десятка вариантов добавить ветку default, то что-то принципиально изменится? Я уже второго человека спрашиваю — тишина.
VE>>>А если v is MyClass? Где передача MyClass onMyClass? HisClass onHisClass? И так для _всех_ типов. VE>>>Именно, что это не аналоги. Как говорится, прочувствуй разницу. VE>>>Теперь понял?
V>>Нет, можно сформулировать почетче?
VE>Количество наследников открыто. Если сделать закрытую иерархию, то можно будет сделать такое преобразование. Но для ООП — это частный случай, и потому оптимизация (чем ты и пытаешься аргументировать). Для ADT же это общий случай, работающий всегда.
Для АлгТД этот случай работает, только если компилятор видит все операции, вызываемые над этим АлгТД.
Т.е. от смены координат ничего ведь не изменяется и не должно. Просто для ООП мы рассуждаем об открытости иерархии, а для ФП — об открытости мн-ва доступных ф-ий.
И да, как раз компилятор С++ показывает, что если программа замкнута, то ему наличие "возможных" наследников до фени. Если их гарантировано не будет, то многое выкидывается нафик.
VE>Как с "любым числом" и enum'ом. Можно, конечно, говорить, что компилятор, который учёл, что у нас всего 3 значения enum'а (red green и blue), провёл суперкомпиляцию, но это не так. Вот если потенциально значение enum'ов бесконечно, но компилятор как-то догадался, что в данном случае их три — то суперкомпиляция. Здесь же ситуация другая.
Здесь ты уже потерял нить обсуждения, т.к. в предложенном тобой преобразовании мы парную упаковку/распаковку АлгТД заменяли на непосредственную обработку данных. А для этого надо заведомо "видеть" все случаи, где этот АлгТД обрабатывается. Я же уже одергивал тебя насчет своеобразной системы модулей Хаскеля, которые на самом деле не модули нихрена, а некий аналог #include из С/С++, с той разницей, что хранится уже распаршенное представление кода. Но этот код не черный ящик ни разу. Интеллектуальную собственность в него не спрячешь, поэтому коммерческих библиотек на Хаскеле нет и не будет. Ну разве что в виде распространяемых в исходниках на честном слове.
VE>Вот в dotnet — это частный случай. А в Haskell — нет.
Т.е. на Хаскель нельзя написать интероперабельную с основной программой на Хаскеле DLL?
VE>Аргументы будут?
Что, опять?
VE>АлгДТ можно преобразовать в алгебру, которая есть кортеж функций.
Угу, в кривое ООП. Америку открыл... Преобразовать-то можно, но ровно с теми же ограничениями, которые идут к LSP.
VE>В общем, без какого-либо осмысленного контраргумента дальше обсуждать тему бессымсленно.
В общем, пора бы взглянуть на реально происходящее и на свои собственные предложения со стороны. Твоя настойчивость насчет отказаться от св-в системы типов и эмулировать другую на основе имеющейся попахивает общим непониманием происходящего, сорри. Ты НЕ понимаешь, что система типов — это уже готовый инструмент, который тебе дан, чтобы ты НЕ писал свой, точно такой же. Пользуйся этим инструментом. Все что я писал здесь — это не критика инструмента, это раскрытие механики его работы и сравнение с механикой динамической типизации в других языках. Я показал, что эта механика абсолютно идентична, как бы тебе не больно было слышать это про "статически типизированный Хаскель". И ты это так и НЕ опровергнул, хотя, повторюсь, придумал несколько способов как избавиться от встроенной динамической типизации, но не так и НЕ понял, что избавляешься каждый раз через LSP, либо через эмуляцию динамической типизации...
Здравствуйте, VoidEx, Вы писали:
V>>Очевидно в том, что при статической типизации никакие проверки в рантайм делать не надо.
VE>Ты не понял. У нас просто код:
VE>Это не проверка типов, просто алгоритм ветвится в зависимости от того, какой выставлен флаг. Почему это не динамическая типизация? Алгоритм работает далее с разными типами данных, делает проверку, чтобы выбрать ветвь.
Ага, а чем отличается код первокурсника от кода опытного программиста? ИМХО, помимо прочего еще тем, что первокурсник всё пишет ручками, а опытный программист умеет заставить работать вместо себя систему типов. Типы-то там нужны для того, чтобы переносить на них часть прикладной логики, правильно? А ты в этом примере решил побыть тем самым первокурсником, не сумевшим расписать иерархию в ООП или АлгТД в ФП? И написал ручками свой if?
V>>В этих твоих мыслительных экспериментах самое примечательное то, что семантически сохраняя поведение программы, ты реализуешь ее то на встроенных проверках аппарата типизации, предоставляемых языком, то выносишь такие проверки из аппарата типизации в пользовательский код, эмулируя похожую механику типизации вручную.
V>>Я же говорю — в правильном направлении копаешь. Еще немного и поймешь, как все работает. Нет в динамической типизации никакой особой магии. В рантайме — это всегда сравнение значений.
VE>Я не копаю, я пытаюсь тебе объяснить, но всё бестолку.
Для начала, сформулируй, что имено ты пытаешься обяснить. Пока что ты ничего не пытаешься мне объяснить, а просто ставишь мысленные эксперименты и ждешь моего одобрения. Ну... одобряю. Если же ты хочешь мне что-то объяснить, плиз, сформулируй, что именно. Т.е. доказательством чего именно должен служить приведенный пример? Мы к нему вернемся, не переживай, давай только определимся, о чем он.
VE>Какие ваши аргументы?