Написание программ без...
От: naf2000  
Дата: 21.10.10 09:43
Оценка:
Используя ЯП с жесткой типизацией можно ли написать достаточно сложную программу (не HelloWord) и стоит ли это делать, в коде которой не будет:
1. Неявных приведений типов: (YourClass) myobject
2. Явных приведений типов: (myobject as YourClass)
3. Проверок типов: myobject is YourClass
4. Интроспекции: myobject.GetType()
5. Конструкций обработок исключений try catch если система не обращается ко внешним неуправляемым ресурсам
Re: Написание программ без...
От: Sshur Россия http://shurygin-sergey.livejournal.com
Дата: 21.10.10 09:48
Оценка:
Здравствуйте, naf2000, Вы писали:

N>Используя ЯП с жесткой типизацией можно ли написать достаточно сложную программу (не HelloWord) и стоит ли это делать, в коде которой не будет:

N>1. Неявных приведений типов: (YourClass) myobject
N>2. Явных приведений типов: (myobject as YourClass)
N>3. Проверок типов: myobject is YourClass
N>4. Интроспекции: myobject.GetType()
N>5. Конструкций обработок исключений try catch если система не обращается ко внешним неуправляемым ресурсам


Если отказаться от ООП — наверно можно C считается "ЯП с жесткой типизацией"? Да и на С# можно при желании в процедурном стиле наваять достаточно сложную программу.

Только точно не нужно.
Шурыгин Сергей

"Не следует преумножать сущности сверх необходимости" (с) Оккам
Re: Написание программ без...
От: Temoto  
Дата: 21.10.10 09:57
Оценка: +1
N>Используя ЯП с жесткой типизацией можно ли написать достаточно сложную программу (не HelloWord) и стоит ли это делать, в коде которой не будет:
N>1. Неявных приведений типов: (YourClass) myobject
N>2. Явных приведений типов: (myobject as YourClass)
N>3. Проверок типов: myobject is YourClass
N>4. Интроспекции: myobject.GetType()
N>5. Конструкций обработок исключений try catch если система не обращается ко внешним неуправляемым ресурсам

Да.
Re: Написание программ без...
От: nikov США http://www.linkedin.com/in/nikov
Дата: 21.10.10 10:02
Оценка:
Здравствуйте, naf2000, Вы писали:

N>Используя ЯП с жесткой типизацией можно ли написать достаточно сложную программу (не HelloWord) и стоит ли это делать, в коде которой не будет:


Можно. На Haskell программы так и пишутся. Причём довольно сложные: компиляторы, системы контроля версий.
Re[2]: Написание программ без...
От: jazzer Россия Skype: enerjazzer
Дата: 21.10.10 10:29
Оценка: +3
Здравствуйте, Temoto, Вы писали:

N>>Используя ЯП с жесткой типизацией можно ли написать достаточно сложную программу (не HelloWord) и стоит ли это делать, в коде которой не будет:

N>>1. Неявных приведений типов: (YourClass) myobject
Типа нельзя привести int к double? Ты поясни, какие именно типы нельзя приводить. А то вот ты хочешь поделить 3 на 5, а в доброй половине языков это будет 0 потому что целочисленная арифметика. И если ты хочешь получить плавающий результат, то тебе так или иначе придется приводить аргумент к плавающему типу.

N>>2. Явных приведений типов: (myobject as YourClass)

То же самое.

N>>3. Проверок типов: myobject is YourClass

В рантайме или во время компиляции?

N>>4. Интроспекции: myobject.GetType()

См. №3.

N>>5. Конструкций обработок исключений try catch если система не обращается ко внешним неуправляемым ресурсам

Исключения — удобный инструмент сообщения об ошибках. Можно, конечно, написать все на кодах возврата, но зачем?

В общем, непонятна цель ограничений. Это какие-то реальные ограничения или так, поговорить?
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: Написание программ без...
От: Alexander G Украина  
Дата: 21.10.10 11:08
Оценка:
Здравствуйте, naf2000, Вы писали:

N>Используя ЯП с жесткой типизацией можно ли написать достаточно сложную программу (не HelloWord) и стоит ли это делать, в коде которой не будет:

N>1. Неявных приведений типов: (YourClass) myobject
N>2. Явных приведений типов: (myobject as YourClass)
N>3. Проверок типов: myobject is YourClass
N>4. Интроспекции: myobject.GetType()
N>5. Конструкций обработок исключений try catch если система не обращается ко внешним неуправляемым ресурсам

Интересно, в контексте этих ограничений является ли вызов унарного конструктора в С++ явным приведением типов?
Если нет, замена (YourClass) myobject на YourClass(myobject) — воркэраунд на первое ограничение.
Русский военный корабль идёт ко дну!
Re: Написание программ без...
От: vdimas Россия  
Дата: 21.10.10 11:17
Оценка: :)
Здравствуйте, naf2000, Вы писали:

N>Используя ЯП с жесткой типизацией можно ли написать достаточно сложную программу (не HelloWord) и стоит ли это делать, в коде которой не будет:

N>1. Неявных приведений типов: (YourClass) myobject
N>2. Явных приведений типов: (myobject as YourClass)
N>3. Проверок типов: myobject is YourClass
N>4. Интроспекции: myobject.GetType()
N>5. Конструкций обработок исключений try catch если система не обращается ко внешним неуправляемым ресурсам

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

Жесткое, в стиле C приведение если и используется, то где-нить в протоколах, сериализованные структуры собирать/разбирать, ибо такое приведение получается гораздо эффективней, чем читать побайтно и сдвигать 8 раз (на x64), вместо того, чтобы сразу прочесть машинное слово.

Ну и еще можно вспомнить про размеченные объединения (алгебраические типы). Их можно сделать жестко-типизированными и безопасными в использовании даже для С, но это именно способ динамической типизации, реализованный в рамках инструментария статической.
Re[2]: Написание программ без...
От: hardcase Пират http://nemerle.org
Дата: 21.10.10 11:48
Оценка:
Здравствуйте, vdimas, Вы писали:

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


Разве это не динамическая диспетчеризация, которую предоставлют механизмы сопоставления с образцом?
/* иЗвиНите зА неРовнЫй поЧерК */
Re[2]: Написание программ без...
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 21.10.10 14:52
Оценка: +1
Здравствуйте, nikov, Вы писали:

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


N>>Используя ЯП с жесткой типизацией можно ли написать достаточно сложную программу (не HelloWord) и стоит ли это делать, в коде которой не будет:


N>Можно. На Haskell программы так и пишутся. Причём довольно сложные: компиляторы, системы контроля версий.


Ну там Type Test заменяется неполным\wildcard паттерном в функции.
Напрмер
data T = A|B|C
f :: T -> a
f A = ...
f _ = ...

фактически функция f эквивалентна конструкции

if (t is A) {} else {}


Только PM оптимизирован для таких операций, а type test в ООП наоборот.
Re: Написание программ без...
От: minorlogic Украина  
Дата: 21.10.10 15:25
Оценка:
Здравствуйте, naf2000, Вы писали:

N>Используя ЯП с жесткой типизацией можно ли написать...


можно.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re: Написание программ без...
От: Eye of Hell Россия eyeofhell.habr.ru
Дата: 21.10.10 18:04
Оценка:

Используя ЯП с жесткой типизацией можно ли написать достаточно сложную программу (не HelloWord) и стоит ли это делать, в коде которой не будет:


Легко. В половине приложений на C++Qt ничего из вышеперчисленного нету за ненадобностью.
Re: Написание программ без...
От: minorlogic Украина  
Дата: 23.10.10 09:22
Оценка:
Скажу больше, надо стараться именно так и писать все время.

Только по приведению типов я не понял , считается ли приведения потомку к предку неявным приведением ?
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[2]: Написание программ без...
От: hardcase Пират http://nemerle.org
Дата: 23.10.10 12:59
Оценка:
Здравствуйте, minorlogic, Вы писали:

M>Скажу больше, надо стараться именно так и писать все время.


M>Только по приведению типов я не понял , считается ли приведения потомку к предку неявным приведением ?


Нет, это использование принципа подстановки на практике.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[3]: Написание программ без...
От: minorlogic Украина  
Дата: 23.10.10 20:17
Оценка:
Здравствуйте, hardcase, Вы писали:

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


M>>Скажу больше, надо стараться именно так и писать все время.


M>>Только по приведению типов я не понял , считается ли приведения потомку к предку неявным приведением ?


H>Нет, это использование принципа подстановки на практике.


Мгм ... ну тогда именно так и необходимо писать , а вы пишете по другому (вопрос не лчно к hardcase а риторически )?
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[3]: Написание программ без...
От: vdimas Россия  
Дата: 23.10.10 20:24
Оценка:
Здравствуйте, hardcase, Вы писали:

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


H>Разве это не динамическая диспетчеризация, которую предоставлют механизмы сопоставления с образцом?


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

Чем же такой подход отличается от обычных скриптовых нетипизированных языков? Лишь тем, что еще в статике задаются ограничения мн-в типов значений, принимаемых в динамике. Например, подтипом дотнетного System.Object является любой дотнетный тип (кроме unsafe указателей), а подтипом варианта Хаскеля — лишь ограниченное множество типов, перечисленное в виде конструкторов варианта.
Re[2]: Написание программ без...
От: vdimas Россия  
Дата: 23.10.10 20:36
Оценка:
Здравствуйте, nikov, Вы писали:

N>Можно. На Haskell программы так и пишутся. Причём довольно сложные: компиляторы, системы контроля версий.


Вряд ли алгебраические типы попадают под понятие "жесткой типизации". Это же абсолютные аналоги VARIANT из COM. Но ведь упомянутый VARIANT по общему мнению за динамическую фичу COM-а сходил. Или надо было вопрошающему определить для нас своё понимание "жесткой типизации".

В общем, это всё рантайм полиморфизм, и мы имеем лишь различные механизмы его реализации: где-то в виде виртуальных ф-ий, где-то в виде алгебраических типов, а где-то в виде ссылки на полное описание типа, как в managed или скриптовых языках. И в общем случае, что можно написать на одной системе с рантайм-полиморфизмом, можно в очень похожем виде (т.е. без дорогостоящей эмуляции отсутствующих фич) написать на другой системе с рантайм-полиморфизмом.
Re[4]: Написание программ без...
От: hardcase Пират http://nemerle.org
Дата: 24.10.10 08:59
Оценка:
Здравствуйте, vdimas, Вы писали:

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


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


Отличие языков со встроенной поддержкой алгебраических типов данных от языков, в которых происходит их эмуляция существующими средствами (Си)в том, что первые умеют (и об уже говорилось) делать консервативные предположения: проверять целостность сопоставления с образцом, тогда как вторые языки делать этого не умеют и оставляют программисту возможность ошибиться.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[5]: Написание программ без...
От: vdimas Россия  
Дата: 24.10.10 12:35
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Отличие языков со встроенной поддержкой алгебраических типов данных от языков, в которых происходит их эмуляция существующими средствами (Си)в том, что первые умеют (и об уже говорилось) делать консервативные предположения: проверять целостность сопоставления с образцом, тогда как вторые языки делать этого не умеют и оставляют программисту возможность ошибиться.


Это зависит от реализации алгебраических типов. Например, там где доступ к членам варианта реализован через статически компилируемый визитор (очень похоже на диспетчеризацию ф-ий в Хаскеле), то линкер просто не скомпилирует программу, если не будут даны определения для всех типов, составляющих вариант, или же, аналогично использования хаскелевского терма '_', не будет дано некоторого определения по-умолчанию.

Там только единственный слабый момент в этой архитектуре — это случай использования одного и того же типа внутри варианта более одного раза, но с разными дискриминаторами.
Решается с помощью способности С++ специализировать шаблоны константами. Т.е. вариант мог бы быть типизирован не просто типом хранимого значения, а парой: значение дискриминатора+тип. И все без дополнительных расходов в рантайм.
Re[3]: Написание программ без...
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 25.10.10 05:01
Оценка: +1
Здравствуйте, vdimas, Вы писали:

V>Вряд ли алгебраические типы попадают под понятие "жесткой типизации". Это же абсолютные аналоги VARIANT из COM. Но ведь упомянутый VARIANT по общему мнению за динамическую фичу COM-а сходил. Или надо было вопрошающему определить для нас своё понимание "жесткой типизации".


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


В общем, если в программе есть if, то она тоже пролетает.
Re[3]: Написание программ без...
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 25.10.10 05:09
Оценка:
Здравствуйте, jazzer, Вы писали:

N>>>5. Конструкций обработок исключений try catch если система не обращается ко внешним неуправляемым ресурсам

J>Исключения — удобный инструмент сообщения об ошибках. Можно, конечно, написать все на кодах возврата, но зачем?

В случае lazy evaluation исключения часто вредны.
Re[4]: Написание программ без...
От: jazzer Россия Skype: enerjazzer
Дата: 25.10.10 05:43
Оценка:
Здравствуйте, lomeo, Вы писали:

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


N>>>>5. Конструкций обработок исключений try catch если система не обращается ко внешним неуправляемым ресурсам

J>>Исключения — удобный инструмент сообщения об ошибках. Можно, конечно, написать все на кодах возврата, но зачем?

L>В случае lazy evaluation исключения часто вредны.

Почему? И почему именно вредны?
Какая тебе разница, откуда прилетит исключение — из одного вызова или из другого?
И какие есть удобные альтернативы, кстати? Я как-то в контексте Хаскеля на эту тему не думал, там только возврат Maybe приходит на ум, но это же несерьезно для нормальной обработки ошибок...
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[5]: Написание программ без...
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 25.10.10 06:08
Оценка:
Здравствуйте, jazzer, Вы писали:

L>>В случае lazy evaluation исключения часто вредны.

J>Почему? И почему именно вредны?
J>Какая тебе разница, откуда прилетит исключение — из одного вызова или из другого?

Так цель исключений — обнаружить местоположение ошибки. В случае ленивости исключение тебе его не покажет.

J>И какие есть удобные альтернативы, кстати? Я как-то в контексте Хаскеля на эту тему не думал, там только возврат Maybe приходит на ум, но это же несерьезно для нормальной обработки ошибок...


Зависит от. Для IO, который по сути strict, используются честные исключения. Назначение типа Maybe -- в описании вычисления, которое может не иметь результата. Посередине находятся исключения на монадах, когда вычисление может вернуть исключение, такой расширенный Maybe. Так что ты всё правильно думаешь.

Ну и ещё, т.к. мы обсуждаем "Конструкции обработок исключений try catch если система не обращается ко внешним неуправляемым ресурсам", то можно ещё предложить мощную систему типов, которая позволяет asserts задавать в типах. В чистых участках кода исключения просто не нужны — их можно включать в возвращаемый тип (OK Result | Fail Reason).

В RWH тоже есть глава
http://book.realworldhaskell.org/read/error-handling.html

Пролистал — вроде по делу.
Re[6]: Написание программ без...
От: jazzer Россия Skype: enerjazzer
Дата: 25.10.10 07:51
Оценка:
Здравствуйте, lomeo, Вы писали:

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


L>>>В случае lazy evaluation исключения часто вредны.

J>>Почему? И почему именно вредны?
J>>Какая тебе разница, откуда прилетит исключение — из одного вызова или из другого?

L>Так цель исключений — обнаружить местоположение ошибки. В случае ленивости исключение тебе его не покажет.


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

J>>И какие есть удобные альтернативы, кстати? Я как-то в контексте Хаскеля на эту тему не думал, там только возврат Maybe приходит на ум, но это же несерьезно для нормальной обработки ошибок...


L>Зависит от. Для IO, который по сути strict, используются честные исключения. Назначение типа Maybe -- в описании вычисления, которое может не иметь результата. Посередине находятся исключения на монадах, когда вычисление может вернуть исключение, такой расширенный Maybe. Так что ты всё правильно думаешь.


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

Тем не менее, для языков типа С++ и прочих Явах исключения, имхо, незаменимы в плане удобства.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[7]: Написание программ без...
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 25.10.10 08:06
Оценка:
Здравствуйте, jazzer, Вы писали:

L>>Так цель исключений — обнаружить местоположение ошибки. В случае ленивости исключение тебе его не покажет.

J>Почему же не покажет? Просто исключение случится в тот момент, где вычисление наконец выполнится, а не в тот момент, когда мы сформировали вызов функции, но это и естественно при ленивости.

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

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


Всё верно. Стека нет, потому бесполезно.

J>Тем не менее, для языков типа С++ и прочих Явах исключения, имхо, незаменимы в плане удобства.


Конечно! Но иногда причиной может быть то, что по другому делать неудобно
Re[8]: Написание программ без...
От: FR  
Дата: 25.10.10 15:43
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Конечно! Но иногда причиной может быть то, что по другому делать неудобно


Ну в том же ML семействе вполне удобно, однако исключения весьма активно используются, притом даже их
использование как управляющих конструкций не считается дурными тоном как в сишном семействе.
Re[7]: Написание программ без...
От: FR  
Дата: 25.10.10 15:44
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Тем не менее, для языков типа С++ и прочих Явах исключения, имхо, незаменимы в плане удобства.


Да для любых строгих (не ленивых) языков удобны.
Re: Написание программ без...
От: Pavel Dvorkin Россия  
Дата: 25.10.10 15:48
Оценка:
Здравствуйте, naf2000, Вы писали:

N>Используя ЯП с жесткой типизацией можно ли написать достаточно сложную программу (не HelloWord) и стоит ли это делать, в коде которой не будет:

N>1. Неявных приведений типов: (YourClass) myobject
N>2. Явных приведений типов: (myobject as YourClass)
N>3. Проверок типов: myobject is YourClass
N>4. Интроспекции: myobject.GetType()
N>5. Конструкций обработок исключений try catch если система не обращается ко внешним неуправляемым ресурсам

Практически ничего из этого нет в Фортране. Достаточно сложные программы на Фортране писали и пишут, но в очень узкой области — расчетов, где почти все это не так уж нужно.
With best regards
Pavel Dvorkin
Re: Написание программ без...
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 25.10.10 15:50
Оценка: :)
Здравствуйте, naf2000, Вы писали:

N>Используя ЯП с жесткой типизацией можно ли написать достаточно сложную программу (не HelloWord) и стоит ли это делать, в коде которой не будет:

N>1. Неявных приведений типов: (YourClass) myobject
N>2. Явных приведений типов: (myobject as YourClass)
N>3. Проверок типов: myobject is YourClass
N>4. Интроспекции: myobject.GetType()
N>5. Конструкций обработок исключений try catch если система не обращается ко внешним неуправляемым ресурсам

В BrainFuck всего этого нет, а язык полон по Тьюрингу. Не говоря уже об ассеблере. И не вспоминая чистый C.
Re[8]: Написание программ без...
От: WolfHound  
Дата: 25.10.10 15:54
Оценка: 1 (1)
Здравствуйте, lomeo, Вы писали:

L>Местоположение в стеке вызовов имеется в виду. Мало толку от исключения, сообщающего, что такой-то assert не сработал, и не сообщающего, в каком именно сценарии.

J>>Другое дело, что при повсеместной композиции функций довольно сложно будет найти концы, если у тебя грохнулась какая-то функция, а она была собрана через десяток других комбинаторов, которых ты в месте падения уже не видишь...
L>Всё верно. Стека нет, потому бесполезно.
Ну не скажи. Мне наверное в 90% случаев если не больше достаточно только строки где исключение вытетело.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[9]: Написание программ без...
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 25.10.10 18:19
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Ну не скажи. Мне наверное в 90% случаев если не больше достаточно только строки где исключение вытетело.


Классика — Exception: Prelude.head: empty list

В общем по разному бывает. Вылетает исключение из какого-нибудь драйвера оракла или потрохов спринга, и только по стеку можно понять, где я налажал.
Re[4]: Написание программ без...
От: vdimas Россия  
Дата: 25.10.10 19:54
Оценка:
Здравствуйте, lomeo, Вы писали:

L>В общем, если в программе есть if, то она тоже пролетает.


Главное, чтобы не вылетала.

-------------
Понятное дело, что поддержка рантайм-полиморфизма для того и есть, чтобы писать меньше этих if. Это как бы система за тебя их пишет. Пусть даже у ней внутре неонка, то бишь вплоть до таблиц переходов.
Re[6]: Написание программ без...
От: vdimas Россия  
Дата: 26.10.10 07:01
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Так цель исключений — обнаружить местоположение ошибки. В случае ленивости исключение тебе его не покажет.


Не понял хода рассуждения. Если значение еще не закешировано в ленивом узле, то будет произведен честный вызов ф-ий по цепочке, т.е. как везде. И место ошибки может показать только stack trace, если этот trace поддерживается системой. Например, в С++ приходится упражняться с его восстановлением или эмулированием. Ну а если значение уже закешировано в узле, то исключение в этом месте возникнуть не может.

L>В чистых участках кода исключения просто не нужны — их можно включать в возвращаемый тип (OK Result | Fail Reason).


Проходили уже. Неудобно, нерасширяемо, неуправляемо в больших проектах. Много лишнего кода.
Re[7]: Написание программ без...
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 26.10.10 08:24
Оценка:
Здравствуйте, vdimas, Вы писали:

L>>Так цель исключений — обнаружить местоположение ошибки. В случае ленивости исключение тебе его не покажет.

V>Не понял хода рассуждения. Если значение еще не закешировано в ленивом узле, то будет произведен честный вызов ф-ий по цепочке, т.е. как везде. И место ошибки может показать только stack trace, если этот trace поддерживается системой. Например, в С++ приходится упражняться с его восстановлением или эмулированием. Ну а если значение уже закешировано в узле, то исключение в этом месте возникнуть не может.

Представь, у нас чистый и ленивый код. В каком порядке он вызывается — неопределено, потому что код чистый и это не имеет значения. Как ты собираешься анализировать полученный stack trace? По сути там и цепочки вызовов, как мы себе их представляем при энергичных вычислениях, нет. Есть лямбда абстракция, которая редуцируется. Получишь ты последние редукции — не цепочку, заметь, это просто куча действий, выполненных в каком-то одному STG известном порядке. Что с ними будешь делать?

L>>В чистых участках кода исключения просто не нужны — их можно включать в возвращаемый тип (OK Result | Fail Reason).

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

Чем неудобно? Почему нерасширяемо (смотри dynamic exceptions в Haskell)? Что значит неуправляемо?

Насчёт много лишнего кода не понял — кода не больше, чем при обычных исключениях.
Re[8]: Написание программ без...
От: vdimas Россия  
Дата: 26.10.10 20:20
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Представь, у нас чистый и ленивый код. В каком порядке он вызывается — неопределено, потому что код чистый и это не имеет значения. Как ты собираешься анализировать полученный stack trace? По сути там и цепочки вызовов, как мы себе их представляем при энергичных вычислениях, нет. Есть лямбда абстракция, которая редуцируется.


Да пускай себе редуцируется. Лямбда же не из воздуха берется? Если рядом с исполняемым модулем есть PDB со ссылками на места в исходнике, где идет определение лямбды, то в стек трейсе пусть будет перечисление этих ссылок на исходник. Этого достаточно.

L>Получишь ты последние редукции — не цепочку, заметь, это просто куча действий, выполненных в каком-то одному STG известном порядке. Что с ними будешь делать?


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

L>Насчёт много лишнего кода не понял — кода не больше, чем при обычных исключениях.


При обычных исключениях мы можем написать один обработчик где-то наверху, а не проверять каждый возвращаемый результат на всех низлежащих уровнях.
Re[9]: Написание программ без...
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 27.10.10 05:37
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Да пускай себе редуцируется. Лямбда же не из воздуха берется? Если рядом с исполняемым модулем есть PDB со ссылками на места в исходнике, где идет определение лямбды, то в стек трейсе пусть будет перечисление этих ссылок на исходник. Этого достаточно.


Это есть.

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


Ну вот есть зашаренный thunk — как будем определять направление вверх? Там же не дерево, там граф. Стек трейса как такового нет. Или вот создали мы какой-то thunk — передали его в функцию, он внутри и сломался. А эта функция ещё из тысячи мест зовётся — как искать прикажешь?

L>>Насчёт много лишнего кода не понял — кода не больше, чем при обычных исключениях.

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

При OK|Fail — то же самое.
Re[6]: Написание программ без...
От: Sinclair Россия https://github.com/evilguest/
Дата: 27.11.10 13:43
Оценка: 29 (2) +1
Здравствуйте, lomeo, Вы писали:

L>Так цель исключений — обнаружить местоположение ошибки.

Ну конечно же нет.
Цель исключений — обработать ошибку в нужном месте. Для энергичных однопоточных вычислений с предсказуемой передачей управления обработка исключений понятна. Есть защищаемые регионы, есть обработчики finally/except/non-except.
При возникновении исключения мы можем относительно легко, а, главное, — предсказуемо, выполнить "раскрутку стека", т.е. определить, кто из обработчиков и в каком порядке должен выполниться.

В случае нетрадиционной передачи управления соответствие между обработчиком и защищаемым регионом теряется.
Начинаются приседания различной степени сложности.
Простая степень сложности: паттерн асинхронных операций, ака Begin.../End...
Раскрутка стека откладывается до момента вызова End... — потому, что в том стеке, где, собсно, выполняется операция, пользовательских обработчиков заведомо нет.
Средняя степень сложности: паттерн "энумератор".
Приседания: yield из catch или finally запрещён, по причинам технической невыполнимости, finally выполняется благодаря злобной магии. Читать здесь и здесь.
Максимальная степень сложности: придумать разумную семантику обработки исключений в CPS.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Написание программ без...
От: GarryIV  
Дата: 29.11.10 10:43
Оценка:
Здравствуйте, naf2000, Вы писали:

N>Используя ЯП с жесткой типизацией можно ли написать достаточно сложную программу (не HelloWord) и стоит ли это делать, в коде которой не будет:

N>1. Неявных приведений типов: (YourClass) myobject
N>2. Явных приведений типов: (myobject as YourClass)
N>3. Проверок типов: myobject is YourClass
N>4. Интроспекции: myobject.GetType()
N>5. Конструкций обработок исключений try catch если система не обращается ко внешним неуправляемым ресурсам

Можно то можно, не так уж и сложно. Только вот нафиг не нужно. Тип объекта это всего лишь его метаинформация — глупо стараться не пользоваться ей без причин. Главное другое — LSP, OCP, SRP etc.
Про try\catch — тут типизация вообще роли не играет. Что в JavaScript, что в Java без них никуда. И дело даже не в наличии неуправляемых ресурсов (с ними try\finally aka using нужен).
WBR, Igor Evgrafov
Re[7]: Написание программ без...
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 30.11.10 01:14
Оценка:
S>Максимальная степень сложности: придумать разумную семантику обработки исключений в CPS.

код cps можно представить как дерево, где каждый лист — это yield, а каждая ветка — это блок кода (хвост блока — тоже является отдельным листом)

при выполнении cps происходит обход дерева в глубину,
если блок кода является циклом, то он обходится много раз подряд пока условие цикла верно,
если блок кода является try, то при возникновении исключения происходит переход на хвост блока (для finally — безусловное, для catch — условное), если исключение не обработано, то происходит дальнейший подъем по дереву с заходом в хвостовые узлы блоков try.

зы
семантика обработки исключений в CPS — логичная, и имеет одно трактование, и, имхо, реализовать try/catch вместе с yield-ами микрософту не позволило лишь какие-то сугубо реализационные заморочки

ззы
при этом считается, что cps в C# реализуется через yield-ы
Re[6]: Написание программ без...
От: mrTwister Россия  
Дата: 30.11.10 10:37
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Так цель исключений — обнаружить местоположение ошибки.


С чего это ты взял?
Цель исключения — это прервать текущий поток выполнения и перейти на специальный поток выполнения для исключений.
лэт ми спик фром май харт
Re[7]: Написание программ без...
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 30.11.10 12:51
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>С чего это ты взял?

T>Цель исключения — это прервать текущий поток выполнения и перейти на специальный поток выполнения для исключений.

Чего это вас потянуло на тему месячной давности?

Выразился я, конечно, не очень. Контекст, однако, был совсем другой. Имелось в виду
(return someCalculation) `catch` (\e -> handle e)

может не перехватить исключение из someCalculation, т.к. в ленивом языке наверх уйдёт thunk. Потом мы действительно куда-то не туда поплыли.

Обсуждать тему _обработки_ исключений не интересно.
Re[4]: Написание программ без...
От: Klapaucius  
Дата: 30.11.10 13:34
Оценка:
Здравствуйте, vdimas, Вы писали:

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


Это не так. Паттерн-мэтчинг проверяет не тип, а конструктор. Т.е. не тип, а тэг.
data Type a b = Constructor1 a | Constructor2 b

тип Type — это тип, известный на этапе компиляции. Constructor1, Constructor2 — конструкторы этого типа, известные на этапе компиляции. Эти конструкторы ПМ и проверяет. Так что полиморфизм тут статический.

V>Чем же такой подход отличается от обычных скриптовых нетипизированных языков? Лишь тем, что еще в статике задаются ограничения мн-в типов значений, принимаемых в динамике. Например, подтипом дотнетного System.Object является любой дотнетный тип (кроме unsafe указателей), а подтипом варианта Хаскеля — лишь ограниченное множество типов, перечисленное в виде конструкторов варианта.


Конструктор алгебраического типа не является его подтипом — конструктор алгтд — это вообще не тип. Через саб/супертайпинг алгтд, бывает, реализуют, особенно в языках для ооп-ориентированных виртмашин вроде CLR или JVM, но каких-то общих выводов из этого делать не следует — это особенности некоторых реализаций и не более того.
Да и сабтайпинг — не обязательно динамика. Бывает полностью статический сабтайпинг.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'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[8]: Написание программ без...
От: Sinclair Россия https://github.com/evilguest/
Дата: 01.12.10 00:08
Оценка:
Здравствуйте, DarkGray, Вы писали:

S>>Максимальная степень сложности: придумать разумную семантику обработки исключений в CPS.


DG>код cps можно представить как дерево, где каждый лист — это yield, а каждая ветка — это блок кода (хвост блока — тоже является отдельным листом)


DG>при выполнении cps происходит обход дерева в глубину,

DG> если блок кода является циклом, то он обходится много раз подряд пока условие цикла верно,
DG> если блок кода является try, то при возникновении исключения происходит переход на хвост блока (для finally — безусловное, для catch — условное), если исключение не обработано, то происходит дальнейший подъем по дереву с заходом в хвостовые узлы блоков try.
Лично мне непонятно, каким образом определить, в хвост которого блока передавать управление.

DG>зы

DG>семантика обработки исключений в CPS — логичная, и имеет одно трактование, и, имхо, реализовать try/catch вместе с yield-ами микрософту не позволило лишь какие-то сугубо реализационные заморочки
А можно ссылку на более подробное описание этой семантики? Я как-то плохо въезжаю после 24-часового перелёта.

DG>ззы

DG>при этом считается, что cps в C# реализуется через yield-ы
Кем считается? Вот, к примеру, малоизвестный парень Эрик считает, что итераторам до CPS далековато.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[9]: Написание программ без...
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 01.12.10 01:42
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


S>>>Максимальная степень сложности: придумать разумную семантику обработки исключений в CPS.


DG>>код cps можно представить как дерево, где каждый лист — это yield, а каждая ветка — это блок кода (хвост блока — тоже является отдельным листом)


DG>>при выполнении cps происходит обход дерева в глубину,

DG>> если блок кода является циклом, то он обходится много раз подряд пока условие цикла верно,
DG>> если блок кода является try, то при возникновении исключения происходит переход на хвост блока (для finally — безусловное, для catch — условное), если исключение не обработано, то происходит дальнейший подъем по дереву с заходом в хвостовые узлы блоков try.

S>Лично мне непонятно, каким образом определить, в хвост которого блока передавать управление.


текущего. какого еще?

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

ззы
приводи непонятный пример, давай его разберем.


DG>>зы

DG>>семантика обработки исключений в CPS — логичная, и имеет одно трактование, и, имхо, реализовать try/catch вместе с yield-ами микрософту не позволило лишь какие-то сугубо реализационные заморочки
S>А можно ссылку на более подробное описание этой семантики? Я как-то плохо въезжаю после 24-часового перелёта.

во-первых, cps полностью подобен обычному коду.
и основная проблема cps аналогична проблеме обычного кода — это goto (хаотичные перескоки между кусками кода).
если от goto избавиться, то мы имеем:
1. иерархию вложенных в друг друга блоков кода(без наличия частично пересекающихся блоков кода). для простоты можно считать, что понятие блок кода(используемое здесь) эквивалентен блоку с фигурными скобками (if/else,цикл,try/using)
2. последовательное исполнение кода (есть только два исключения: break/return/throw — переход к концу одного из блоков в который вложена текущая позиция, continue — переход к началу одного из блоков в который вложена текущая позиция)
3. cps с такой структурой легко представим в виде yield enumerator-а

DG>>ззы

DG>>при этом считается, что cps в C# реализуется через yield-ы
S>Кем считается? Вот, к примеру, малоизвестный парень Эрик считает, что итераторам до CPS далековато.

он там пишет, что можно было сделать более универсально, но не пишет что далековато.
основная проблема, что yield enumerator неудобно стыкуется с callback-ами, и необходимо использовать разные трюки для этого.
Re[10]: Написание программ без...
От: Sinclair Россия https://github.com/evilguest/
Дата: 02.12.10 00:33
Оценка:
Здравствуйте, DarkGray, Вы писали:


S>>Лично мне непонятно, каким образом определить, в хвост которого блока передавать управление.

DG>текущего. какого еще?
DG>у тебя же дерево, и есть текущий выполняемый лист, этот лист входит в какую-то ветку дерева, которая и есть блок — в хвост которого и надо передать управление.
Я не вижу никакого дерева. В каждый момент у нас есть только исполняемая функция и продолжение, которое нужно вызвать, когда она закончится. При этом стека никакого нет, благодаря tail call optimization.


DG>ззы

DG>приводи непонятный пример, давай его разберем.
Ок. Давай посмотрим на простейший пример из википедии.
(define (pyth x y k)
 (* x x (lambda (x2)
   (* y y (lambda (y2)
     (+ x2 y2 (lambda (x2py2)
       (sqrt x2py2 k))))))))

Предположим, у нас один из * кидает исключение (из-за целого переполнения). Где он будет обработан?

DG>во-первых, cps полностью подобен обычному коду.

Не совсем. В CPS я могу реализовывать произвольные виды call flow, а не только вложение и последовательное исполнение.

DG>и основная проблема cps аналогична проблеме обычного кода — это goto (хаотичные перескоки между кусками кода).

DG>если от goto избавиться, то мы имеем:
DG>1. иерархию вложенных в друг друга блоков кода(без наличия частично пересекающихся блоков кода). для простоты можно считать, что понятие блок кода(используемое здесь) эквивалентен блоку с фигурными скобками (if/else,цикл,try/using)
DG>2. последовательное исполнение кода (есть только два исключения: break/return/throw — переход к концу одного из блоков в который вложена текущая позиция, continue — переход к началу одного из блоков в который вложена текущая позиция)
В CPS нет никаких return. "Выход" из блока не происходит никогда.
DG>3. cps с такой структурой легко представим в виде yield enumerator-а

DG>>>ззы

DG>>>при этом считается, что cps в C# реализуется через yield-ы
S>>Кем считается? Вот, к примеру, малоизвестный парень Эрик считает, что итераторам до CPS далековато.

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

Он пишет, что CPS — это более общий случай сопрограмм. А они — более общий случай блоков итераторов.
DG>основная проблема, что yield enumerator неудобно стыкуется с callback-ами, и необходимо использовать разные трюки для этого.
Основная проблема в том, что блоки итераторов реализуют только подмножество CPS. И уже это вызывает неоднозначности в трактовке исключений.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[11]: Написание программ без...
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 02.12.10 13:49
Оценка:
S>>>Лично мне непонятно, каким образом определить, в хвост которого блока передавать управление.
DG>>текущего. какого еще?
DG>>у тебя же дерево, и есть текущий выполняемый лист, этот лист входит в какую-то ветку дерева, которая и есть блок — в хвост которого и надо передать управление.
S>Я не вижу никакого дерева. В каждый момент у нас есть только исполняемая функция и продолжение, которое нужно вызвать, когда она закончится. При этом стека никакого нет, благодаря tail call optimization.

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

программу можно представить в виде ориентированного графа: где вершины — это куски кода, а ребра — переходы между кусками кода.

теоретическое отступление (только существенное):

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

и соответственно, если граф можно свести к дереву, то задача здорово упрощается

но орграф можно свести однозначно к дереву только при отсутствие частично перекрывающих циклов
пример: граф A->B->C->D где дополнительно есть ребра C->A и D->B невозможно однозначно свести к дереву.

не образуют частично перекрывающих циклов в коде следующие конструкции: function/call/return плюс блочные конструкции if/then,for/loop/while/break/continue,try/catch/throw, using.
частично перекрывающие циклы образуются только при бесконтрольном применении goto

резюме:
орграф кода можно однозначно свести к дереву при отсутствии goto, образующих частично перекрывающие циклы

следствие 1:
если код представлен в виде дерева — то время жизни (и видимости) переменной от места объявление до выхода из данного узла в вверх

следствие 2:
если код представлен в виде дерева — то можно выделить основную последовательность выполнения кода, который подобен обходу дерева в глубину

следствие 3:
каждый узел дерева после своего выполнения возвращает результат: результат в том числе может быть void(ничего) либо exception(ошибка)

следствие 4:
все операции которые изменяют порядок выполнения можно свести к следующему базису:
1. блок function + call
2. блок loop + break(пропуск следующих ветвей на данному уровне и переход на конец блока loop)+continue(пропуск следующих ветвей на данному уровне и переход на начало блока loop
3. блок if/then/else — в зависимости от условия выполняется блок then, но пропускается else, либо наоборот
4. блок try/catch_finally
catch_finally можно представить как блок вида:

catch_finally(результат)//результат - это результат блока кода, который внутри try (см. п. 3)
{
  //безусловный кусок кода (это аналогично finally из main-stream языков)
  bla-bla
  //эти if-ы аналогичны блокам catch из main-stream языков
  if(результат is NullException)
  {
    bla-bla
    return void;//NullException обработан
  }
  if(результат is ArgumentException)
  {
    bla-bla
    return результат; //аналогично throw; внутри catch
  }
  if(результат is exception) //обработка произвольного исключения
    bla-bla
}



следствие 5:
возврат на предыдущую ветку возможен только косвенно с помощью блока цикла и операции continue

следствие 6:
пропуск выполнения веток может быть только с помощью оператора условия

следствие 7:
при возникновении исключения код обходится аналогично п.2, но при этом пропускаются все блоки, кроме блока catch_finally(результат)
или другими словами, все блоки кроме catch_finally выглядят как:
if (current_result is not exception)
{
  bla-bla
}
else
 return current_result;


следствие 8:
при обходе дерева инвариантом хранимого состояния является:
1. текущее положение в дереве (аналогично регистру ip в процессоре)
2. состояние локальных переменных текущего блока(узла) и всех узлов, в который этот узел вложен (аналогичен стеку из обычного описания работы программы)


S>...


зы
конкретный разбор продолжу позже
Re[12]: Написание программ без...
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.12.10 02:00
Оценка:
Здравствуйте, DarkGray, Вы писали:
DG>CPS-программа (построенная на callback-ах) подобна такой же обычной программе (построенной на goto).
DG>подобие эквивалентное — callback отображается в goto, все остальное остается без изменений.
Не совсем так, но в целом они, конечно же, эквивалентны. turing completeness.
DG>программу можно представить в виде ориентированного графа: где вершины — это куски кода, а ребра — переходы между кусками кода.
Можно.
DG>теоретическое отступление (только существенное):
DG>

DG>но далее известно, что граф с точки зрения обработки намного менее удобный, чем дерево.
DG>при любой обработке необходимы такие операции как: обойти всю структуру, разбить структуру на несколько, склеить структуру из нескольких, отобразить одну структуру на другую, выделить инвариант и т.д. и т.п.
DG>все эти операции для дерева решаются намного проще и однозначнее, чем для графа.
DG>для кода, если он представлен в виде дерева, а не графа, то понятнее решаются задачи — время жизни переменных, движение исключения и т.д.
Это всё хорошо. Вот только в общем случае CPS я не вижу никаких гарантий деревообразности.

DG>но орграф можно свести однозначно к дереву только при отсутствие частично перекрывающих циклов
DG>пример: граф A->B->C->D где дополнительно есть ребра C->A и D->B невозможно однозначно свести к дереву.

DG>не образуют частично перекрывающих циклов в коде следующие конструкции: function/call/return плюс блочные конструкции if/then,for/loop/while/break/continue,try/catch/throw, using.
DG>частично перекрывающие циклы образуются только при бесконтрольном применении goto
Ещё раз намекаю: в CPS нет никаких return.

DG>следствие 1:
DG>если код представлен в виде дерева — то время жизни (и видимости) переменной от места объявление до выхода из данного узла в вверх
Повторно намекаю: в CPS направление "вверх" имеет другой смысл.


DG>следствие 3:
DG>каждый узел дерева после своего выполнения возвращает результат: результат в том числе может быть void(ничего) либо exception(ошибка)
Отлично. Только в случае CPS узел не "возвращает" результат. Как раз наоборот: узел передаёт результат дальше.
То есть мы, конечно, можем попробовать развернуть оба call flow. То есть, функция принимает не одно продолжение, а сразу два: на случай "нормального" и "исключительного" развитий событий. Тем не менее, способ сделать catch всё ещё непонятен.

DG>следствие 4:
DG>все операции которые изменяют порядок выполнения можно свести к следующему базису:
DG>1. блок function + call
DG>2. блок loop + break(пропуск следующих ветвей на данному уровне и переход на конец блока loop)+continue(пропуск следующих ветвей на данному уровне и переход на начало блока loop
DG>3. блок if/then/else — в зависимости от условия выполняется блок then, но пропускается else, либо наоборот
DG>4. блок try/catch_finally
DG>catch_finally можно представить как блок вида:
DG>

DG>catch_finally(результат)//результат - это результат блока кода, который внутри try (см. п. 3)
DG>{
DG>  //безусловный кусок кода (это аналогично finally из main-stream языков)
DG>  bla-bla
DG>  //эти if-ы аналогичны блокам catch из main-stream языков
DG>  if(результат is NullException)
DG>  {
DG>    bla-bla
DG>    return void;//NullException обработан
DG>  }
DG>  if(результат is ArgumentException)
DG>  {
DG>    bla-bla
DG>    return результат; //аналогично throw; внутри catch
DG>  }
DG>  if(результат is exception) //обработка произвольного исключения
DG>    bla-bla
DG>}
DG>

Очередной вопрос: о каком именно return идёт речь? В CPS return нету.

DG>следствие 5:
DG>возврат на предыдущую ветку возможен только косвенно с помощью блока цикла и операции continue

DG>следствие 6:
DG>пропуск выполнения веток может быть только с помощью оператора условия

DG>следствие 7:
DG>при возникновении исключения код обходится аналогично п.2, но при этом пропускаются все блоки, кроме блока catch_finally(результат)
DG>или другими словами, все блоки кроме catch_finally выглядят как:
DG>
DG>if (current_result is not exception)
DG>{
DG>  bla-bla
DG>}
DG>else
DG> return current_result;
DG>


DG>следствие 8:
DG>при обходе дерева инвариантом хранимого состояния является:
DG>1. текущее положение в дереве (аналогично регистру ip в процессоре)
DG>2. состояние локальных переменных текущего блока(узла) и всех узлов, в который этот узел вложен (аналогичен стеку из обычного описания работы программы)

Что имеется в виду под "вложением" в случае CPS? На всякий случай ещё раз напомню: в CPS всякий раз, когда тебе хочется написать return a; ты делаешь вместо этого continue(a).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[13]: Написание программ без...
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 03.12.10 11:27
Оценка:
S>Это всё хорошо. Вот только в общем случае CPS я не вижу никаких гарантий деревообразности.

а в обычном коде видешь?
вот, например, в этом:
void main()
{
  int x = 7;
  int q = 4;
  int z = 7;
  lab2:
  switch (x)
  {
     case 0:
       z = 3;
     case 15:
       printf ("%d", x);
       x = 17;
       goto lab3;
     case 16:
       x -= 40;
       if (x < -100)
        goto lab7;
       z -= 2;
       break;
    case 17:
       z = 5;
       x+=2;
       break;
    case 18:
       z--;
       break;
    lab7:
      q = 0;
    case 19:
       z++;
       q = 10;
       break;
    lab4:
    default:
      while(x > 4 && q > 0)
      {       
        x -= 15;
       lab3:
        q--;
      }
      break;
    case 37:
      return;
  }
  goto lab2;
}


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



S>Ещё раз намекаю: в CPS нет никаких return.


есть, семантика return — это выход из именованого блока,
после этого передается управление следующему блоку (и эта семантика не зависит — код обычный или cps):
в обычном коде — это называется return, и реализуется через pop указателя со стандартного stack-а и переходе по нему,
в cps — это называется continue, часто реализуется через вызов функции, может реализовываться через переход по указателю, может реализовываться через снятие указателя со _своего_ stack-а и переходе на него.

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

DG>>следствие 1:

DG>>если код представлен в виде дерева — то время жизни (и видимости) переменной от места объявление до выхода из данного узла в вверх
S>Повторно намекаю: в CPS направление "вверх" имеет другой смысл.

ты о семантике, или опять о названиях?

DG>>следствие 3:

DG>>каждый узел дерева после своего выполнения возвращает результат: результат в том числе может быть void(ничего) либо exception(ошибка)
S>Отлично. Только в случае CPS узел не "возвращает" результат. Как раз наоборот: узел передаёт результат дальше.
S>То есть мы, конечно, можем попробовать развернуть оба call flow. То есть, функция принимает не одно продолжение, а сразу два: на случай "нормального" и "исключительного" развитий событий. Тем не менее, способ сделать catch всё ещё непонятен.

и какая разница — как назвать? что блок возвращает или передает результат?
байты что ли от этого по другому в коде лягут?

S>Очередной вопрос: о каком именно return идёт речь? В CPS return нету.


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


S>Что имеется в виду под "вложением" в случае CPS? На всякий случай ещё раз напомню: в CPS всякий раз, когда тебе хочется написать return a; ты делаешь вместо этого continue(a).


cps можно представить в виде дерева, а в дереве все узлы куда-то вложены.

зы
кстати стоит зафиксировать — какое ключевое отличие CPS от обычного кода.
какой у тебя кстати критерий для выделения cps?
Re[14]: Написание программ без...
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.12.10 13:46
Оценка:
Здравствуйте, DarkGray, Вы писали:

S>>Это всё хорошо. Вот только в общем случае CPS я не вижу никаких гарантий деревообразности.


DG>а в обычном коде видешь?

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



S>>Ещё раз намекаю: в CPS нет никаких return.


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

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

DG>ты о семантике, или опять о названиях?

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

DG>и какая разница — как назвать? что блок возвращает или передает результат?

DG>байты что ли от этого по другому в коде лягут?
Давай не будем пока углубляться в байты. Байты управляются бэк-эндом; нас пока интересует семантика.

DG>о том самом который делает выход из текущего именноваго блока, и не важно как он при этом называется в том или ином языке



S>>Что имеется в виду под "вложением" в случае CPS? На всякий случай ещё раз напомню: в CPS всякий раз, когда тебе хочется написать return a; ты делаешь вместо этого continue(a).


DG>cps можно представить в виде дерева, а в дереве все узлы куда-то вложены.

Не надо повторять утверждения. Надо обосновывать.
DG>зы
DG>кстати стоит зафиксировать — какое ключевое отличие CPS от обычного кода.
DG>какой у тебя кстати критерий для выделения cps?
Вместо return выполняется вызов переданного в функцию continuation. В очередной раз намекну: в обычном стиле можно вернуться только в одно место — то, откуда вызвали. В CPS я могу делать "возврат" в произвольное количество мест. Именно поэтому CPS более выразителен, чем классический call flow.

Ты почему-то продолжаешь упорно рассматривать обычный код, отказываясь обсуждать CPS. В обычном коде семантика исключений чётко прописана и понятна — это я написал с самого начала. В CPS лично мне она непонятна. Я задал вопрос с примером кода. Ответа нет.
Ок, давай я попробую придумать более близкий пример на C#.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: Написание программ без...
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 03.12.10 14:56
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Ты почему-то продолжаешь упорно рассматривать обычный код, отказываясь обсуждать CPS. В обычном коде семантика исключений чётко прописана и понятна — это я написал с самого начала. В CPS лично мне она непонятна. Я задал вопрос с примером кода. Ответа нет.


А ты понимаешь, как с помощью продолжений выразить выброс/перехват исключения?
Re[15]: Написание программ без...
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 03.12.10 15:18
Оценка:
S> В CPS я могу делать "возврат" в произвольное количество мест. Именно поэтому CPS более выразителен, чем классический call flow.

так это зло, а не польза (фактически — это будет аналог longjmp-а). в итоге получается write-only-логика работы программы, которую потом через полгода (а тем более если это другой чел) и с литром водки не разобрать.

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

например:
static IEnumerable<object> Task(string text)
{
  foreach (var ch in text)
  {
    Console.WriteLine(ch);
    yield return null; 
  }
}
static void Main()
{
  var task1 = Task("Hello").GetEnumerator();
  var task2 = Task("World").GetEnumerator();
  for (;;)
  {
    if(!task1.MoveNext() & !task2.MoveNext())
      break;    
  }
}


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

например, вот следующий код (особенно если почистить и половину служебного кода убрать в библиотеку) нагляден и понятен в отличие от спагетти на callback-ах
    static IEnumerable<F> Task(string text)
    {
      foreach (var ch in text)
      {
        Console.WriteLine("{0}: {1}", watch.Elapsed, ch);
        yield return null;
      }
    }
    static IEnumerable<F> Task2(AutoResetEvent wait, string host, int port)
    {
      using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
      {
        var f = new F { wait = wait };
        f.result = socket.BeginConnect(host, port, f.OnEnd, null);
        yield return f;
        try
        {
          socket.EndConnect(f.result);
          Console.WriteLine("{0}: connection to {1}, {2}", watch.Elapsed, host, port);
        }
        catch (Exception exc)
        {
          Console.WriteLine("{0}: not connected to {1}, {2}", watch.Elapsed, host, port);
          //yield return exc
        }
      }
    }
    static void Main()
    {
      var wait = new AutoResetEvent(false);
      watch.Start();

      var task1 = Task("Hello, world");
      var task2 = Task2(wait, "ya.ru", 80);
      var task3 = Task2(wait, "200.0.0.1", 80);

      Run(wait, 1000, task1, task2, task3);

    }

    static void Run(WaitHandle wait, int idletimeout, params IEnumerable<F>[] tasks)
    {
      var _tasks = tasks.Select(task => task.GetEnumerator()).ToArray();
      for (; ; )
      {
        var isRun = false;
        foreach (var task in _tasks)
        {
          if (task.Current == null || task.Current.IsEnd)
          {
            if (task.MoveNext())
              isRun = true;
          }
          else
            isRun = true;
        }
        if (!isRun)
          break;

        wait.WaitOne(1000);
      }

    }

    static System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
    class F
    {
      public AutoResetEvent wait;
      public void OnEnd(IAsyncResult result)
      {
        this.result = result;
        Console.WriteLine("{0}: OnEnd", watch.Elapsed);
        if (wait != null)
          wait.Set();
      }
      public bool IsEnd { get { return result != null && result.IsCompleted; } }
      public IAsyncResult result;
    }

и вот для этого кода имеет смысл рассуждать как должны обрабатываться exception-ы
Re[16]: Написание программ без...
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.12.10 21:35
Оценка:
Здравствуйте, DarkGray, Вы писали:

DG>так это зло, а не польза (фактически — это будет аналог longjmp-а). в итоге получается write-only-логика работы программы, которую потом через полгода (а тем более если это другой чел) и с литром водки не разобрать.

(Вздыхает). Остальное человечество почему-то думает наоборот:

This, along with a restrictive style prohibiting a variety of constructs usually available, is used to expose the semantics of programs, making them easier to analyze. This style also makes it easy to express unusual control structures, like catch/throw or other non-local transfers of control.


DG>основная полезность CPS — это возможность "снаружи" прерывать поток управления на время для выполнения какого-то другого действия.

Основная полезность CPS — возможность строить свои управляющие конструкции в дополнение к тем, которые уже есть в языке.
Возможность асинхронного выполнения — не более чем побочный эффект, связанный с отсутствием стека. Поясняю: "аппаратный" поток вынужден хранить своё состояние (регистры+стек) во время "сна". В CPS стека нет, есть только указатель в текущую функцию. Именно поэтому можно иметь миллионы "логических" потоков управления, не исчерпывая адресное пространство.


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


DG>прерывание выполнение потока управления очень полезно когда делается долгое внешнее действие: чтение файла, обращение по сети, получение данных из базы, и на cps удобно класть асинхронные куски, записывая при этом их в нормальном виде, а не в виде спагетти, когда одна фигня вызывает другую фигню через callback.


DG>например, вот следующий код (особенно если почистить и половину служебного кода убрать в библиотеку) нагляден и понятен в отличие от спагетти на callback-ах

DG>и вот для этого кода имеет смысл рассуждать как должны обрабатываться exception-ы
Для этого — не имеет. Для него уже вопросы обработки исключений тщательно разобраны. Я про них, кстати, упоминал.
А вообще — вы изобретаете poor man's asynchrony.
Тут сразу стоит обсуждать исключения в C#5 с await/async.

Про спагетти на коллбэках — вот например чрезвычайно трудноанализируемый код:

void buttonHandler() {
    // This is executing in the Swing UI thread.
    // We can access UI widgets here to get query parameters.
    final int parameter = getField();
 
    new Thread(new Runnable() {
        public void run() {
            // Now we're in a separate thread.
            // We can do things like hit a database or access
            // a blocking resource like the network to get data.
            final int result = lookup(parameter);
 
            javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    // Now we're back in the UI thread and can use
                    // the fetched data to fill in UI widgets.
                    setField(result);
                }
            });
        }
    }).start();

По-моему, можно разобраться и без бутылки и даже без комментариев. И это ещё убогий джавасинтаксис с кучей мусора.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[16]: Написание программ без...
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.12.10 21:44
Оценка:
Здравствуйте, lomeo, Вы писали:

L>А ты понимаешь, как с помощью продолжений выразить выброс/перехват исключения?

http://blogs.msdn.com/b/ericlippert/archive/2010/10/22/continuation-passing-style-revisited-part-two-handwaving-about-control-flow.aspx
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[17]: Написание программ без...
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 03.12.10 22:10
Оценка:
S>Основная полезность CPS — возможность строить свои управляющие конструкции в дополнение к тем, которые уже есть в языке.

пример такой полезной управляющей структуры?
Re[17]: Написание программ без...
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 03.12.10 22:24
Оценка:
S> В CPS стека нет, есть только указатель в текущую функцию. Именно поэтому можно иметь миллионы "логических" потоков управления, не исчерпывая адресное пространство.

и та же зачистка dispose-ов делается в ручную?
Re[18]: Написание программ без...
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.12.10 02:47
Оценка:
Здравствуйте, DarkGray, Вы писали:

S>> В CPS стека нет, есть только указатель в текущую функцию. Именно поэтому можно иметь миллионы "логических" потоков управления, не исчерпывая адресное пространство.


DG>и та же зачистка dispose-ов делается в ручную?

Не знаю. CPS в дотнете, как такового, нет. В схеме нет IDisposable. Поэтому не очень понятно, что и как делается.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[17]: Написание программ без...
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 04.12.10 09:46
Оценка:
Здравствуйте, Sinclair, Вы писали:

L>>А ты понимаешь, как с помощью продолжений выразить выброс/перехват исключения?

S>http://blogs.msdn.com/b/ericlippert/archive/2010/10/22/continuation-passing-style-revisited-part-two-handwaving-about-control-flow.aspx

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

В обычном коде семантика исключений чётко прописана и понятна — это я написал с самого начала. В CPS лично мне она непонятна.

Ведь это просто один из паттернов использования самих продолжений.
Re[19]: Написание программ без...
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 04.12.10 12:36
Оценка:
S>Не знаю. CPS в дотнете, как такового, нет. В схеме нет IDisposable. Поэтому не очень понятно, что и как делается.

в том-то и дело, что cps в общем виде без генерализованного потока управления — очень сложен для обозримости, понимания, модификации, объединения с другими концепциями и т.д.

и соответственно, такой cps может быть полезен для реализации каких-то сложных библиотек/framework-ов, но в конечном коде — такой cps подобен обезьяне с гранатой (тут можно провести аналогию, что "cps с произвольными переходами" vs "cps с генерализованным потоком управления" аналогичен "память с произвольным доступом по указателю" vs "память с защищенными доступом").
первая фича — конечно намного мощнее и выразительнее, но намного хуже поддается хоть какому-нибудь контролю и предсказуемости.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.