Здравствуйте, FR, Вы писали:
FR>"ошибка" там намереная чтобы показать что паскаль не подерживает замыкания. FR>Даже если вызывать вложенную функцию, все равно не работает: FR>
Давай вместе разберемся.
Переменная n определена в функции fget; lget возвращает значение этой самой переменной n; через func мы вызываем lget.
В твоем примере вызов func приводит к тому, что lget возвращает "мусор".
Отсюда ты, кажется, делаешь правдоподобный вывод, что причина в том, что ты вызвал lget "снаружи", и в Паскале нет замыканий.
ИМХО, настоящая причина возврата "мусора" вместо n в том, что переменная n больше не существует.
Дело не в том, что процедуру вызвали "снаружи", а в том, что функция fget уже завершила работу, и ее локальных объектов больше не существует.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Хоар
Re[18]: Паттерны суть слабости языков программирования
Здравствуйте, AVC, Вы писали:
AVC>Дело не в том, что процедуру вызвали "снаружи", а в том, что функция fget уже завершила работу, и ее локальных объектов больше не существует.
Как раз "снаружи" и получается, т.к. fget завершила свою работу и уничтожила все переменные, замыкание сделать не получается, чтд.
Re[19]: Паттерны суть слабости языков программирования
Здравствуйте, Курилка, Вы писали:
К>Здравствуйте, AVC, Вы писали:
AVC>>Дело не в том, что процедуру вызвали "снаружи", а в том, что функция fget уже завершила работу, и ее локальных объектов больше не существует.
К>Как раз "снаружи" и получается, т.к. fget завершила свою работу и уничтожила все переменные, замыкание сделать не получается, чтд.
Я приводил пример с вызовом из внешней ("наружной") процедуры callback.
Процедура callback не может знать о локальных переменных процедуры p; несмотря на это, код работает.
"Снаружи" здесь следует понимать в лексическом смысле.
Вот одно из определений замыкания, хотя, вероятно, и не лучшее: http://ru.wikipedia.org/wiki/Замыкание_(программирование)
В программировании, Замыкание (англ. closure) — это процедура, которая ссылается на свободные переменные в своём лексическом контексте.
Замыкание, так же как и экземпляр объекта, есть способ представления функциональности и данных, связанных и упакованных вместе.
Замыкание — это особый вид функции. Она определена в теле другой функции и создаётся каждый раз во время её выполнения. В записи это выглядит как функция, находящаяся целиком в теле другой функции. При этом вложенная внутренняя функция содержит ссылки на локальные переменные внешней функции. Каждый раз при выполнении внешней функции происходит создание нового экземпляра внутренней функции, с новыми ссылками на переменные внешней функции.
Замыкание связывает код функции с её лексическим окружением (местом, в котором она определена в коде). Лексические переменные замыкания отличаются от глобальных переменных тем, что они не занимают глобальное пространство имён. От переменных в объектах они отличаются тем, что привязаны к функциям, а не объектам.
Речь, ИМХО, все время идет только о лексическом окружении.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Хоар
Re[20]: Паттерны суть слабости языков программирования
Здравствуйте, AVC, Вы писали:
AVC>Речь, ИМХО, все время идет только о лексическом окружении.
А кто спорит? Хотя бывают и динамического скоупа замыкания, но это не интересно.
Вопрос в том, что замыкание можно передать "наружу", и с ним будет передаваться контекст (именно лексический).
У FR как раз и показана попытка сделать это.
Но не вызвать изнутри контекста (что у тебя и происходит), а именно передать, чтобы вызвать совершенно в другом контексте.
Re[11]: Паттерны суть слабости языков программирования
Здравствуйте, FR, Вы писали:
FR>Просто нужно реализовать нормальное замыкание, Вирт сказал А но не сказал B. Реально для такого примитивного (извини ) языка как оберон просто нормальные замыкания и фвп (включая лямбду) дало бы очень много.
Сомневаюсь. Мне кажется, замыкания вообще противопоказаны императивным языкам.
Closures Considered Harmful
For a number of years I have been familiar with the observation that the quality of programmers is a decreasing function of the density of closures in the programs they produce...
FR>Хотя конечно еще нужна полиморфность функций.
А вот это стопудофф.
Re[21]: Паттерны суть слабости языков программирования
Здравствуйте, Курилка, Вы писали:
К>Вопрос в том, что замыкание можно передать "наружу", и с ним будет передаваться контекст (именно лексический). К>У FR как раз и показана попытка сделать это. К>Но не вызвать изнутри контекста (что у тебя и происходит), а именно передать, чтобы вызвать совершенно в другом контексте.
Можешь ли ты показать, в каком именно месте вызов вложенных процедур в Паскале не соответствует понятию "замыкания"?
Я такого места (пока) не наблюдаю.
В 7-й главе "Красного дракона" Ахо, Ульмана и Сети (в разделе Параметры-процедуры) написано:
Правила лексической области видимости применимо и в том случае, когда вложенная процедура передается в качестве параметра.
После чего идет пример именно на Паскале.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Хоар
Re[22]: Паттерны суть слабости языков программирования
Здравствуйте, AVC, Вы писали:
AVC>Здравствуйте, Курилка, Вы писали:
К>>Вопрос в том, что замыкание можно передать "наружу", и с ним будет передаваться контекст (именно лексический). К>>У FR как раз и показана попытка сделать это. К>>Но не вызвать изнутри контекста (что у тебя и происходит), а именно передать, чтобы вызвать совершенно в другом контексте.
AVC>Можешь ли ты показать, в каком именно месте вызов вложенных процедур в Паскале не соответствует понятию "замыкания"? AVC>Я такого места (пока) не наблюдаю.
ОК, реализуй то, что показано в примере в определении википедиевском на Паскале а не на схеме. Конкретного определения не дам, к сожалению...
FR как раз и попытался сделать что-то подобное, но... — результат ты сам знаешь.
AVC>В 7-й главе "Красного дракона" Ахо, Ульмана и Сети (в разделе Параметры-процедуры) написано: AVC>
AVC>Правила лексической области видимости применимо и в том случае, когда вложенная процедура передается в качестве параметра.
AVC>После чего идет пример именно на Паскале.
И что с лексической областю видимости? К ней претензий не было. Или это ты просто так для красного словца?
Re[12]: Паттерны суть слабости языков программирования
Здравствуйте, Трурль, Вы писали:
Т>Здравствуйте, FR, Вы писали:
FR>>Просто нужно реализовать нормальное замыкание, Вирт сказал А но не сказал B. Реально для такого примитивного (извини ) языка как оберон просто нормальные замыкания и фвп (включая лямбду) дало бы очень много.
Т>Сомневаюсь. Мне кажется, замыкания вообще противопоказаны императивным языкам.
Если осторожно, то ничего страшного. В той же схеме очень интенсивно используют и ничего
Т> Т>
Closures Considered Harmful
Т> For a number of years I have been familiar with the observation that the quality of programmers is a decreasing function of the density of closures in the programs they produce...
Почему?
Re[22]: Паттерны суть слабости языков программирования
Здравствуйте, AVC, Вы писали:
AVC>Можешь ли ты показать, в каком именно месте вызов вложенных процедур в Паскале не соответствует понятию "замыкания"? AVC>Я такого места (пока) не наблюдаю.
Вот в этом месте:
Каждый раз при выполнении внешней функции происходит создание нового экземпляра внутренней функции, с новыми ссылками на переменные внешней функции.
из твоей цитаты. При этом этот вновь созданный экземпляр живет уже после того как функция отработала. При этом этот экземпляр (замыкание) это функция + все переменные которые используются внутри этой функции, их время жизни также продляется.
AVC>В 7-й главе "Красного дракона" Ахо, Ульмана и Сети (в разделе Параметры-процедуры) написано: AVC>
AVC>Правила лексической области видимости применимо и в том случае, когда вложенная процедура передается в качестве параметра.
AVC>После чего идет пример именно на Паскале.
Я думаю здесь просто путаница лексическая область != лексическому замыканию
Re[23]: Паттерны суть слабости языков программирования
Здравствуйте, FR, Вы писали:
AVC>>Можешь ли ты показать, в каком именно месте вызов вложенных процедур в Паскале не соответствует понятию "замыкания"? AVC>>Я такого места (пока) не наблюдаю.
FR>Вот в этом месте: FR>
FR>Каждый раз при выполнении внешней функции происходит создание нового экземпляра внутренней функции, с новыми ссылками на переменные внешней функции.
FR>из твоей цитаты.
Это-то как раз для Паскаля выполняется: каждому новому вызову внешней функции соответствует новый линк во вложенной процедуре.
На всякий случай замечу, что вложенная процедура в Паскале устроена несколько иначе, чем функция в Си.
FR>При этом этот вновь созданный экземпляр живет уже после того как функция отработала. FR>При этом этот экземпляр (замыкание) это функция + все переменные которые используются внутри этой функции, их время жизни также продляется.
А вот этого в "моей" вики-цитате как раз нет.
Но, если несколько утрировать, ты считаешь, что "замыкание" несовместимо с автоматическими (стековыми) локальными переменными?
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Хоар
Re[24]: Паттерны суть слабости языков программирования
Здравствуйте, AVC, Вы писали:
AVC>Это-то как раз для Паскаля выполняется: каждому новому вызову внешней функции соответствует новый линк во вложенной процедуре. AVC>На всякий случай замечу, что вложенная процедура в Паскале устроена несколько иначе, чем функция в Си.
Я знаю (вернее только смутные воспоминания ), но в паскале не выполняется условие, что после вызова внешней функции все замкнутые переменные должны остатся живыми.
FR>>При этом этот вновь созданный экземпляр живет уже после того как функция отработала. FR>>При этом этот экземпляр (замыкание) это функция + все переменные которые используются внутри этой функции, их время жизни также продляется.
AVC>А вот этого в "моей" вики-цитате как раз нет. AVC>Но, если несколько утрировать, ты считаешь, что "замыкание" несовместимо с автоматическими (стековыми) локальными переменными?
Вполне совместимо, если копировать их значения в некий контекст. Например в питоне каждая функция имеет скрытый атрибут func_closure в котором хранятся ссылки на нужные переменные. В C# функция с замыканием реализуется в виде скрытого класса хранящего как поля все нужные переменные.
Здравствуйте, WoldemaR, Вы писали:
WR>Здравствуйте, Курилка, Вы писали:
К>>Тогда объясни — зачем вообще тебе это нужно: "текст который нельзя править".
WR>А для отладки. Кнопочку нажал — текст развернулся — можно отлаживаться. WR>Кнопочку нажал — текст свернулся.
Вы сейчас описали работу будущего IntelliSence для Nemerle применительно к макросам
+ Бесплатно типобезопасный генератор (сами макросы)
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[25]: Паттерны суть слабости языков программирования
Здравствуйте, FR, Вы писали:
AVC>>Это-то как раз для Паскаля выполняется: каждому новому вызову внешней функции соответствует новый линк во вложенной процедуре. AVC>>На всякий случай замечу, что вложенная процедура в Паскале устроена несколько иначе, чем функция в Си.
FR>Я знаю (вернее только смутные воспоминания ), но в паскале не выполняется условие, что после вызова внешней функции все замкнутые переменные должны остатся живыми.
Возможно, именно в этом и заключается причина, почему "замыкание" (или конструкция, сходная с "замыканием"), еще возможное в Паскале, отсутствует в Модуле-2 и Обероне.
Это, конечно, только догадка, но вот как это примерно выглядит.
В Паскале "замыкания" были возможны, потому что в нем не было процедурных переменных (сразу вспоминаю старую статью Пайка с рефреном "tyranny of Pascal" ).
Поэтому время жизни "замкнутых" переменных не играло особой роли: ведь указатель на вложенную процедуру нельзя было сохранить в переменной и использовать после уничтожения контекста.
Как только в Модуле появились процедурные переменные, это условие уже больше не соблюдалось, и возник запрет на присвоение вложенных процедур процедурным переменным.
Вероятно, по этой же причине "замыканий" нет и в Обероне. (Конечно, их можно заменить "функторами", как это принято в Си++. Но это отдельная тема.)
Кажется, логика в этой догадке есть; правда, не мешало бы уточнить факты (например, что можно было, а что нельзя в старом Паскале).
AVC>>Но, если несколько утрировать, ты считаешь, что "замыкание" несовместимо с автоматическими (стековыми) локальными переменными?
FR>Вполне совместимо, если копировать их значения в некий контекст. Например в питоне каждая функция имеет скрытый атрибут func_closure в котором хранятся ссылки на нужные переменные. В C# функция с замыканием реализуется в виде скрытого класса хранящего как поля все нужные переменные.
Интересно, как это сказывается на эффективности?
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Хоар
Re[26]: Паттерны суть слабости языков программирования
Здравствуйте, AVC, Вы писали:
AVC>Здравствуйте, FR, Вы писали:
AVC>>>Это-то как раз для Паскаля выполняется: каждому новому вызову внешней функции соответствует новый линк во вложенной процедуре. AVC>>>На всякий случай замечу, что вложенная процедура в Паскале устроена несколько иначе, чем функция в Си.
FR>>Я знаю (вернее только смутные воспоминания ), но в паскале не выполняется условие, что после вызова внешней функции все замкнутые переменные должны остатся живыми.
AVC>Возможно, именно в этом и заключается причина, почему "замыкание" (или конструкция, сходная с "замыканием"), еще возможное в Паскале, отсутствует в Модуле-2 и Обероне. AVC>Это, конечно, только догадка, но вот как это примерно выглядит. AVC>В Паскале "замыкания" были возможны, потому что в нем не было процедурных переменных (сразу вспоминаю старую статью Пайка с рефреном "tyranny of Pascal" ).
Точно не было?
То есть никакого аналога на сишные указатели на функции?
Тогда замыкания просто бессмысленны, и их точно не могло там быть.
AVC>Поэтому время жизни "замкнутых" переменных не играло особой роли: ведь указатель на вложенную процедуру нельзя было сохранить в переменной и использовать после уничтожения контекста. AVC>Как только в Модуле появились процедурные переменные, это условие уже больше не соблюдалось, и возник запрет на присвоение вложенных процедур процедурным переменным.
Но в том же обероне вместе с GC появилась и возможность сохранять контекст.
AVC>Вероятно, по этой же причине "замыканий" нет и в Обероне. (Конечно, их можно заменить "функторами", как это принято в Си++. Но это отдельная тема.)
Это также удобно как эмулировать классы на си
AVC>Кажется, логика в этой догадке есть; правда, не мешало бы уточнить факты (например, что можно было, а что нельзя в старом Паскале).
AVC>>>Но, если несколько утрировать, ты считаешь, что "замыкание" несовместимо с автоматическими (стековыми) локальными переменными?
FR>>Вполне совместимо, если копировать их значения в некий контекст. Например в питоне каждая функция имеет скрытый атрибут func_closure в котором хранятся ссылки на нужные переменные. В C# функция с замыканием реализуется в виде скрытого класса хранящего как поля все нужные переменные.
AVC>Интересно, как это сказывается на эффективности?
Зависит от компилятора. Если брать Ocaml (как наиболее близкий к статическим Оберону и C++) то оптимизирутеся намертво, то есть так же как в хороших C++ компиляторах вплоть до превращения функции с замыканием в ассемблерную инструкцию заталкивающую число на стек
Re[27]: Паттерны суть слабости языков программирования
Здравствуйте, FR, Вы писали:
AVC>>В Паскале "замыкания" были возможны, потому что в нем не было процедурных переменных (сразу вспоминаю старую статью Пайка с рефреном "tyranny of Pascal" ).
FR>Точно не было? FR>То есть никакого аналога на сишные указатели на функции? FR>Тогда замыкания просто бессмысленны, и их точно не могло там быть.
Отнюдь.
Процедурных переменных, действительно, не было. Но были (в дополнение к параметрам-значениям и параметрам-переменным) параметры-процедуры и параметры-функции.
Т.к. функция в Паскале не могла вернуть функцию или процедуру, то процедуры/функции могли передаваться только вперед (т.е. вниз по стеку вызовов) и никогда назад (как, к слову, было в твоем примере).
Мне кажется, что это гарантировало, что параметр-процедура/параметр-функция не мог "пережить" свой контекст.
Следовательно, передача в качестве параметра вложенной процедуры/функции не могло привести к ошибке, подобной ошибке в твоем примере (для конструирования такой ошибки тебе потребовалась процедурная переменная).
AVC>>Поэтому время жизни "замкнутых" переменных не играло особой роли: ведь указатель на вложенную процедуру нельзя было сохранить в переменной и использовать после уничтожения контекста. AVC>>Как только в Модуле появились процедурные переменные, это условие уже больше не соблюдалось, и возник запрет на присвоение вложенных процедур процедурным переменным.
FR>Но в том же обероне вместе с GC появилась и возможность сохранять контекст.
Разве что ценой значительной потери эффективности.
А ведь Оберон все-таки эффективный язык.
AVC>>Вероятно, по этой же причине "замыканий" нет и в Обероне. (Конечно, их можно заменить "функторами", как это принято в Си++. Но это отдельная тема.)
FR>Это также удобно как эмулировать классы на си
Давай посмотрим на это с немного более абстрактной точки зрения.
Действительно ли цель в том, чтобы имитировать в императивном языке "замыкания", или же важно передавать функцию вместе с данными?
С такой общей задачей объекты вполне справляются и без "замыканий".
А как говорил Эйнштейн, "два мыла — это слишком сложно".
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Хоар
Re[28]: Паттерны суть слабости языков программирования
AVC>Отнюдь. AVC>Процедурных переменных, действительно, не было. Но были (в дополнение к параметрам-значениям и параметрам-переменным) параметры-процедуры и параметры-функции. AVC>Т.к. функция в Паскале не могла вернуть функцию или процедуру, то процедуры/функции могли передаваться только вперед (т.е. вниз по стеку вызовов) и никогда назад (как, к слову, было в твоем примере). AVC>Мне кажется, что это гарантировало, что параметр-процедура/параметр-функция не мог "пережить" свой контекст. AVC>Следовательно, передача в качестве параметра вложенной процедуры/функции не могло привести к ошибке, подобной ошибке в твоем примере (для конструирования такой ошибки тебе потребовалась процедурная переменная).
может и так, но мне это малоинтересно
FR>>Но в том же обероне вместе с GC появилась и возможность сохранять контекст.
AVC>Разве что ценой значительной потери эффективности. AVC>А ведь Оберон все-таки эффективный язык.
Практика показывает что ты не прав, компиляторы Ocaml'а почти не уступают хорошим си компиляторам. Реально потеря эффективности вполне сравнима с потерями от использования классов, то есть часто равна нулю.
AVC>>>Вероятно, по этой же причине "замыканий" нет и в Обероне. (Конечно, их можно заменить "функторами", как это принято в Си++. Но это отдельная тема.)
FR>>Это также удобно как эмулировать классы на си
AVC>Давай посмотрим на это с немного более абстрактной точки зрения.
Это точка быстро скатывается до уровня машиного кода
AVC>Действительно ли цель в том, чтобы имитировать в императивном языке "замыкания", или же важно передавать функцию вместе с данными?
Цель ввести в язык мощное средство позволяющее создавать более сложные абстракции и писать более понятный и компактный код. При том не требующее так не любимого Виртом усложнения синтаксиса. Я не спорю что любые высокоуровневые средства можно эмулировать более низкоуровневыми, но это всегда криво и куча лишней ненужной писанины, ничего ни дающей а только скрывающей смысл.
AVC>С такой общей задачей объекты вполне справляются и без "замыканий".
В лиспе и схеме объекты реализуются через замыкания.
AVC>А как говорил Эйнштейн, "два мыла — это слишком сложно".
А мыло и стиральный порошок?
Re[13]: Паттерны суть слабости языков программирования
Здравствуйте, FR, Вы писали:
FR>Если осторожно, то ничего страшного. В той же схеме очень интенсивно используют и ничего
Что хохлу в радость, то свинье — смерть.
Re[14]: Паттерны суть слабости языков программирования
Здравствуйте, Трурль, Вы писали:
Т>Здравствуйте, FR, Вы писали:
FR>>Если осторожно, то ничего страшного. В той же схеме очень интенсивно используют и ничего Т>Что хохлу в радость, то свинье — смерть.
А почему куда потерял?
Re[7]: Паттерны суть слабости языков программирования
Здравствуйте, kan, Вы писали: kan>Паттерн — вещь абстрактная, и каждая его имплементация — конкретизация, а следовательно потеря общности.
Почему ты так думаешь?
Очень многие паттерны, или их заметные части, вполне поддаются встраиванию в язык. Ок, давайте забъем на доисторические паттерны вроде "наследования", которые давно встроены в языки программирования.
Паттерн Abstract Factory. Для С++ это именно "абстрактный паттерн", который нужно конкретизировать для каждого случая. В Delphi реализация этого паттерна вшита в язык: достаточно написать перед именем конструктра слово "virtual", и автоматически будет создана соответствующая фабрика. Причем семейство этих фабрик будет автоматически приводимо друг к другу, что моделируется достаточно сложным и неортогональным кодом на С++. В итоге в Delphi сделать абстрактную фабрику в разы проще, и гораздо меньше шанс совершить ошибку.
Далее, посмотрим на Publisher-Subscriber.
Вот у нас есть совершенно абстрактная вещь. При ее реализации на классическом ЯП есть некоторое количество грабель. Ок, добавляем в C# ключевое слово event, и оно мгновенно вполне конкретизирует нашу абстракцию, позволяя нам избегать примитивных ошибок при реализации подписки/отписки. Заодно делая использование события проще не только со стороны подписчика, но и со стороны публикатора.
В старой джаве был такой Enum Pattern — за неимением нормальной поддержки енумов. Казалось бы, совершенно абстрактная вещь: "создайте класс, в нем набор static final полей...". Ан нет, в 1.6 встроили в язык — и засиял себе паттерн, позволяя существенно экономить код, опять же сокращая количество ошибок.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: Паттерны суть слабости языков программирования
Здравствуйте, kan, Вы писали:
kan>Или даже какой язык может предоставить специальную конструкцию для этого паттерна?
Ну давай подумаем, как выглядит фасад, и придумаем вымышленный синтаксис. Почему бы не сделать язык, который при построении класса указать список классов, для которых он выступает фасадом, и не получить автоматически код? Ведь код фасада обычно примитивен. kan>Паттерн — вещь абстрактная, и каждая его имплементация — конкретизация, а следовательно потеря общности.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.