B>Почему в этом коде нет неструктурированной передачи управления, а в Smalltalk есть?
Найн, найн. Когда я делал мой аналог, я пытался установить соответствие 1:1 Java-объектов и объектов из Smalltalk. Единственное, я не пошёл до самого конца и не превратил "element = object ifTrue: [BLOCK]" в вызов метода для объекта Boolean — и так уже создание экземпляров CodeBlock вылилось в нехилый оверхед.
Здесь же ты (можно на "ты"?) привёл идеологически совершенно другой код: в коде на Смоллтоке итерация как бы "внутренняя", а в твоём коде на Яве "внешняя".
У тебя нет возвращения "true" "изнутри". Чтобы вернуть true "изнутри", мне пришлось кинуть исключение ReturnTrue, чтобы создать близкий аналог СТ-кода.
И всё равно полного аналога не получилось!
Чтобы получить полный аналог, надо как-то эмулировать исполнение в "домашнем" фрейме, а в Яве (и вообще в любом структурном языке) код исполняется только в _текущем_ фрейме. (Термин фрейм — стандартный, мы можем наблюдать фрейм функции в отладчике, когда сделаем step into в эту функцию). Вот поэтому этот приём и производит впечатление неструктурированного.
Можно изменить свою точку зрения и считать, что все блоки в СТ исполняются в текущем фрейме, но! континуэйшн-блоки (см ниже) перед выполнением формируют свой фрейм получая доступ к данным из домашнего фрейма, и если такого доступа нет, то выбрасывается исключение. Довольно витиевато, но имхо привычнее.
Я разумеется нашёл вполне конкретное и доступное объяснение блоков.
It is useful to distinguish between two kinds of blocks:
1. Those that end with a return expression. We will call these continuation blocks (there is no standard, concise term). For example: [:x :y| ^x+y]
2. Those not ending in a return expression, which we will call simple blocks.
When a simple block completes evaluation, it returns its value (the result of evaluating the last message expression in the block) to the method that sent it the message (the sender). (это понятно — прим. перев.)
When a continuation block completes evaluation it returns its result to the method that activated its home context.
Отсюда правило:
A simple block can be evaluated many times; a continuation block can be evaluated at most once.
b := [ :x | Transcript show: x. ^x ].
b value: 'a'; value: 'b' "ERRRROR!!!"
Так что моя точка зрения следующая:
1. Континуэйшн-блоки в СТ нарушают некоторые правила стандартного структурного программирования. Или можно переформулировать так: континуэйшн-блоки создают нестандартную стурктуру исполнения программ.
2. Подозреваю, что правило сформулированное абзацем выше позволяет избежать всех граблей связанных с "Context cannot return error" и вообще с континуэйшн-блоками. Ну или если нет, то пожалуйста (обращаюсь ко всем Смоллтоковцам) сформулируйте мне такое правило.
Замечу, что до второго вызова управление не дойдёт вообще.
LCR>2. Подозреваю, что правило сформулированное абзацем выше позволяет избежать всех граблей связанных с "Context cannot return error" и вообще с континуэйшн-блоками. Ну или если нет, то пожалуйста (обращаюсь ко всем Смоллтоковцам) сформулируйте мне такое правило.
Повторный вызов "умершего" блока блока это логическая ошибка. Такая же как, например, использование уже закрытого файла. "Повторный вызов" проявит себя так же — выбросит исключение. Естественно, исключение будет брошено в контексте использования блока, а не в контексте определения блока.
Что касается правил, то код, который является безопасным по отношению к исключениям (использует finaly), так же безопасный по отношению к нелокальному возврату (так как при нелокальном возврате будут вызваны все finaly, которые называются ensure: в ST). Такой код нужно писать и в Java и в Nemrle — _всегда_.
ЗЫ. Простите, не сдержался. Это точно мой последний пост про нелокальные возвраты на ближайшие три месяца.
ЗЗЫ. Если будете мусолить эту тему дальше, то постепенно дойдёте до вреда состояний вообще. Потому как, после исключения объект может остаться в невалидном состоянии.
ЗЗЗЫ. А там и до статической типизации vs. динамической не далеко.
Andrei N.Sobchuck,
ANS>Повторный вызов "умершего" блока блока это логическая ошибка. Такая же как, например, использование уже закрытого файла. "Повторный вызов" проявит себя так же — выбросит исключение. Естественно, исключение будет брошено в контексте использования блока, а не в контексте определения блока.
Это понятно. Короче, получаем краткое и чёткое правило: "не вызывай умерший блок".
ANS>ЗЫ. Простите, не сдержался. Это точно мой последний пост про нелокальные возвраты на ближайшие три месяца. ANS>ЗЗЫ. Если будете мусолить эту тему дальше, то постепенно дойдёте до вреда состояний вообще. Потому как, после исключения объект может остаться в невалидном состоянии. ANS>ЗЗЗЫ. А там и до статической типизации vs. динамической не далеко.
Спасибо за разъяснение. Можешь отдыхать, лично мне всё понятно
Здравствуйте, VladD2, Вы писали:
VD>Этот разговор начался с того, что выражение содержало в себе блок с ^ которая приводила к тому, что выражение не завершалось при некотором условии.
VD>То что это нельзя сделать в арифмитическом выражении — это конечно хорошо. Но вот то что присвоение переменной может не произойти в следсвии хакерских выпендрежей мне категорически не нравится.
Прошу прощения, мне показалось, что речь идет о том, что есть опасность неочевидного прерывания вычисления выражения за счет манипулирования блоками с оператором "^". При этом мне показалось, что обсуждаемым неочевидным случаем является получения такого "плохого" блока из вне. Был не прав.
Наверное, самая плохая ситуация с блоками в Smalltalk может выглядеть примерно так:
SomeClass>>foo
...
a := [... ^1.]
...
b := ... (a value) ... "выражение, содержащего вызов блока с оператором возврата"
...
При вызове такого метода до присваивания значения переменной b дело не дойдет.
Однако, как уже отмечалось, такая ситуация является экзотикой да и Smalltalk никогда не навешивал на себя медаль "Абсолютно безопасный".
Ситуацию может сгладить система автоматической проверки кода (Code Critic).
По крайней мере в VisualWorks она доступна в стандартном браузере класса.
Так вот, метод, подобный показанному выше, будет пойман правилом "Method with full blocks".
Позволю себе привести описание правила из документации:
Methods with full blocks. Checks for methods that contain full blocks
or create a context with the thisContext
keyword. These methods are a place where
inefficiencies can creep in. For example, a
common reason why a full block is created is
because a block assigns a temporary
variable that is not defined inside the block. If
the temporary variable is only used inside
the block, then the definition of the
temporary should be moved inside the block.
The "move to inner scope" refactoring can be
used to correct this.
Отмечу, что "Code Critic" --- не некоторая экзотическая тулза, а легкое и всегда доступное средство. (Всего в "Code Critic" около сотни различных проверок в пяти разделах. И никто не мешает писать свои).
Это все я написал к тому, что оценивать ту или иную среду можно только в комплексе, а в случае Smalltalk это особенно актуально.
VD>Отмечу, что безопасный язык отличается от небезопасного тем, что в нем нельзя применять отровенно плохие приемы, а в небезопасном всего лишь не рекомендуется.
Баланс между строгими запретами и рекомендациями --- очень тонкая вещь, лежащая, в основном, на совести создателей языка. К тому же прием не становится откровенно плохим только от того, что есть лучшее решение. На мой взгляд, плохим приемом стоит считать только тот, который приводит к неочевидным, трудно находимым ошибкам, чего здесь не наблюдается.
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR> Я не об этом, а о том, что фразы вполне терпимы, особенно если учитывать контекст и (предполагаемый) возраст.
Это прямые и косвенные оскорбления, надменность и хмаство нормально?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Что касается исключений. И так, ты зарегистрирова некий лисенер. При вызове лисенера он бросил NPE. Превратился ли в этот момент Java/C# в небезопасный неструктурный язык?
Он приведет к неработоспособной программе.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
ANS>>Что касается исключений. И так, ты зарегистрирова некий лисенер. При вызове лисенера он бросил NPE. Превратился ли в этот момент Java/C# в небезопасный неструктурный язык?
VD>Он приведет к неработоспособной программе.
Тяжело вам там в .Net. В ST не работала бы только одна функция.
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Здравствуйте, VladD2, Вы писали:
ANS>>>Что касается исключений. И так, ты зарегистрирова некий лисенер. При вызове лисенера он бросил NPE. Превратился ли в этот момент Java/C# в небезопасный неструктурный язык?
VD>>Он приведет к неработоспособной программе.
ANS>Тяжело вам там в .Net. В ST не работала бы только одна функция.
А в ST остальные ф-ции, вызвавшие "не работающую" магическим образом будут работать?
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Здравствуйте, Курилка, Вы писали:
К>>А в ST остальные ф-ции, вызвавшие "не работающую" магическим образом будут работать?
ANS>Всей программе, как карточному домику, не обязательно рассыпатся.
Ну и что будет делать вызывающая функция в таком случае?
Придумает возвращаемое значение?
VladD2,
LCR>> Я не об этом, а о том, что фразы вполне терпимы, особенно если учитывать контекст и (предполагаемый) возраст.
VD>Это прямые и косвенные оскорбления, надменность и хамство нормально?
Ммм.. Нет, конечно. Но и твоя, и моя оценка субъективна. Возможно, я не прав и слишком далеко прочертил границу дозволенного. Ладно, в бане — так в бане. Не смертельно.
Здравствуйте, VladD2, Вы писали:
B>>Представьте макрос if (cond) then {trueBlock} else {falseBlock} B>>Вы передаете блоки в качестве параметров макроса. Если Вы напишите return в этих блоках, будет это являться неструктурируемой передачей управления?
VD>Несомненно, нет, не будет! Но! Я не могу передать if в другую функцию и return не приведет к выходу из другой процедуры где бы код не был бы обявлен.
Если такое сделать на Smalltalk то будет сгенерировано исключение.
VD>То есть для пользователя мароса if возрват будет происходить всегда предсказуемо структруно.
Для пользователя метода ifTrue:ifFalse: даже если передать в них блок с ^ возврат будет происходить всегда предсказуемо.
B>>Возврат из блоков в Smalltalk используется для завершения работы текущего метода (в котором описан блок) с передачей результата.
VD>Вот это то и плохо. Это приводит к "замынанию управления". И это прождает не структрность и непредсказуемость. В других языках лямбды замыкаются исключительно на данные. При этом данные разделяются между контекстом замыкания и замой лямбдой, что делает код не противоричивым даже если сама лямбда будет передана в совершенно другой контест и при пройдет через тысячи функций или даже полей классов.
Вы можете не использовать это. Аналогичной функциональности можно добиться и без использования возврата из блока. Так же как например Вы можете не писать в Java и С# return в ветке if, а дойти до конца метода и выполнить return.
VD>Да, в твоих примерах это так, и я уверен, что авторы Смолтока именно на такое применение и рассчитывали. Но вот к глубокому сожалению есть варианты когда применение "крышлки" приводитк к проблемам. И это уже косяк в дизайне языка. Именно по этому подобных вещей нет в современных ЯП. Вместо этого в них есть куда более сложные фишки вроде континюэшонов и старые добрые лямбды знакомые еще по Лиспу.
Я просил привести такой пример. Без этого я не вижу смысла это обсуждать
Здравствуйте, VladD2, Вы писали:
VD>Ага. А в С++ нет проблем goto, обращения к неинициализированным переменным и т.п. Достаточно послушать фанатов С++, чтобы убедиться что те у кого такие проблемы встречаются — это просто криворукие ламеры.
Собственно, так и есть.
VD>Вы, поклонники Смолтока, сидите на этих комнях и упорно их не видите. Для меня это очевидные грабли. Для вас вполне нормальная вещь.
Грабли видят (точнее, ощущают, те, кто на них наступают). Если смолторкеры говорят, что они программируют на SmallTalk и не натыкаются на эти грабли, а ты, не программируя на SmallTalk, говоришь, что видишь эти грабли... То для стороннего наблюдателя твое мнение выглядит, по меньшей мере странным. Ладно бы ты говорил про аналогии в других языках (как это часто делается про обсуждении макросов в Nemerle и макросов в других языках). Так ведь нет.
В Ruby, к примеру, блок кода можно создать либо через Proc.new (конструирование путем создания нового экземпляра объекта-блока), либо методом Kernel#lambda:
Блоки, созданные через Proc.new ведут себя так же, как блоки с ^ в SmallTalk (по крайней мере, насколько я понял из описаний смолтолкеров) -- применение в чужом контексте приведет к порождению исключения. Блоки, созданные через lambda, напротив, не прерывают работу вызвавшего их кода -- происходит возврат только из тела лямбды:
irb(main):001:0> def sample(&block)
irb(main):002:1> block.call
irb(main):003:1> end
=> nil
irb(main):004:0> sample &Proc.new { return }
LocalJumpError: unexpected return
from (irb):4
from (irb):2:in `sample'
from (irb):4
irb(main):005:0> sample &lambda { return }
=> nil
irb(main):006:0>
И при работе в Ruby я лично ни разу не видел, чтобы это стало граблями. Ни разу.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Sinclair, Вы писали:
ГВ>>Почему я никакой маскировки не заметил? Что я сделал не так? S>Не прочитал.
Что за гнусные инсинуации! Разумеется, прочитал. И всё равно не оскорбился. Ну искрит время от времени, велика важность! ИМХО, с этого вреда гораздо меньше, чем с высказываний типа: "Кто не следует майнстриму, у того нет ума".
S>>>И уж успешность его в жизни — не знаю, личной там или профессиональной, — вызывает обоснованные сомнения. ГВ>>В контексте программистского форума мне его личная жизнь совсем не интересна. И твои (а также Влада и остальных) догадки о ней — тем паче. S>Ну почему же. Очень интересна.
Я ж тебе говорю, это не ко мне. Кто где работает, кто чьих будет, у кого какой диагноз, кто есть что — это на кухне под пиво потрындеть. Да и то темы посодержательнее найти можно.
<< Под музыку: silent >>
<< При помощи Януса: 1.2.0 alpha rev. 650 >>
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, Master Yoda, Вы писали:
_>>имхо тоже хороший ответ. емкий и лаконичный
MY>Емкость и лаконичность подразумевает не только краткость высказывания, но и значительный, а также полезный смысл заключенный в нем. Кроме обвинения меня в ламеризме обернутого в изящную форму я ничего в приведенных вами цитатах не вижу.
W>> И ведь ни TeX, ни Metafont не помянули. DEC VMS как будто и не существовало...
MY>Аналогично
Вот зачем, зачем так явно расписываться в ламеризме?!?
Последняя фраза — рефрен к "автор — ламер". Вовсе не в твой адрес. Так что видишь ты тут не правильно.
А ты сам не иронизировал бы про "одни мы, ламеры, нервно курим в сторонке", так и не нарвался бы на ответную иронию.
MY>Было бы интересно узнать, что же интересного нашли там вы, может я действительно что-то проглядел.
MY>Кстати аппеляция к понятию "ламеризм", которое не имеет четко определенной семантики, понимается разными людьми по разному (для Win2K — это, например, незнание некоторых инструментов программистом) и место которому только в низкосортных флеймах, уже сама по себе говорит о его непоследовательности и нелогичности.
Знаешь, порой много экономичнее вместо долгого разбора по кусочкам, многокилобайтного вычисления ошибок и их разбора, вычленения неправомерных обобщений и усилений... В общем, вместо анализа просто сказать: автор — ламер. Тем более, когда такие вещи видны не вооружённым глазом.
<< Под музыку: silent >>
<< При помощи Януса: 1.2.0 alpha rev. 650 >>
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, Дарней, Вы писали:
V>>Преимущество в легкости освоения и дешевизне интеграции. Д>у кого преимущество? перед кем? интеграции с чем? Д>высказался, как в лужу пукнул
Может, хватит мусорить?
<< Под музыку: silent >>
<< При помощи Януса: 1.2.0 alpha rev. 650 >>
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, Дарней, Вы писали:
ГВ>>Окстись! Слово-то такое "Lisp" слышали не все, а пользоваться им умеют и не боятся ещё более редкие представители. Из этих редких единиц ещё более редкие единицы действительно будут стартапить. Не все же спят и видят, как бы заняться собственным стартапом. Откуда тут "волна" стартапов выпрыгнет? Д>Ты опять ставишь всё с ног на голову. Начнем с того, что стартапят далеко не "редкие единицы".
Заблуждение. Если бы хоть 6% программистов (60% от всех Хороших Програмистов ) поднимали свои стартапы, то был бы тайфун стартапов.
Д>Из хороших программистов 99,9% хотя бы раз задумывалось об открытии своего дела, задолбавшись исполнять команды идиота-руководителя А большинство из них не только думает, но и делает — иначе они не были бы хорошими программистами.
Угу. Типа стартап — это писать то, что тебе в кайф, а деньги сами в карман сыплются.
Д>Да, хороших программистов мало. Но у плохих всё равно нет никаких шансов поднять свой стартап, поэтому их не стоит вообще принимать в рассмотрение.
Заблуждение.
Д>Далее. Неважно, знают они Лисп, Смоллток или Хаскелл изначально. Любой хороший программист выбирает инструмент под задачу, и проводит предварительные исследования, эксперименты, прежде чем начать реальную работу. Писать на языке Х "потому что я его уже хорошо знаю" — это прерогатива плохих программистов.
Заблуждение. Гламурное к тому же.
Д>Если инструмент дает реальные преимущества — значит, выберут именно его. И неважно, требует он предварительного привыкания или нет — тем более что для хорошего программиста это не составит никаких проблем, не так ли?
Ага, а параллельно для хорошего програмиста не составит никаких проблем выполнять функции бухгалтера, директора, администратора и т.п.
<< Под музыку: silent >>
<< При помощи Януса: 1.2.0 alpha rev. 650 >>
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, Дарней, Вы писали:
Д>Ну это уже дурь. Зачем писать прописью математические вычисления, когда есть вполне привычная математическая нотация?
О. Это просто удивительно, что только ни делают люди.
Я одно время писал код под удивительную систему G2. Такая штука для построения экспертных систем. У нее был удивительнейший внутренний язык программирования. Рассчитан типа на не-программистов, а "простых экспертов" в некой области.. Потому очень сильно был привязан к английской граматике. Не знаю как эксперты, а программисты у нас от него все плевались.
В том языке много было удивительных вещей, но меня лично больше всего поразило, что он понимал и требовал(!) использование артиклей(!!) и, хуже того, различал артикли 'a' и 'an' по правилам английского языка (гласная-согласная) и требовал их правильного(!!!) применения!
Это было мега.
Уже — к счастью — стерлись детали синатксиса, но было что-то типа так:
if the obj is an object then ...(а с просто "а" - будет ошибка!)
if the obj is a someOtherObject then ...