Здравствуйте, Gaperton, Вы писали:
G>4) Самое сложное. Надо добавить возможность функции брать в качестве аргумента выражение (функцию) после скобок.
Может быть здесь пригодилась бы предлагаемая Страуструпом перегрузка пробела?
Здравствуйте, Трурль, Вы писали:
Т>Здравствуйте, Gaperton, Вы писали:
G>>4) Самое сложное. Надо добавить возможность функции брать в качестве аргумента выражение (функцию) после скобок. Т>Может быть здесь пригодилась бы предлагаемая Страуструпом перегрузка пробела?
Не, по моему и так неплохо получилось. Только осталась еще одна одна маленькая проблема — с break, continue и return внутри безымянных {} блоков, а так — все хорошо.
Ну, это в целом тоже просто. Вводим еще одно правило — употребление имени функции типа void() при условии, что она не является, аргументом функции, эквивалентно вызову этой функции.
Эксцепшены будем ловить внутри for. Остался return — это жесткач. Вводим дополнительное правило — return, употребленный внутри безымянной функции void() приводит не только к выходу из нее, но к выходу из первой функции по стеку, не имеющей в определении модификатора passthrough (или defmacro - привет Lisp-ерам ). На функцию for вешаем модификатор passthrough, остальные функции по умолчанию его не имеют. Таким образом, у нас return будет работать корректно, как и раньше.
Интересная задачка из серии занимательный С++ , не находишь?
Здравствуйте, Gaperton, Вы писали:
G>Эксцепшены будем ловить внутри for. Остался return — это жесткач. Вводим дополнительное правило — return, употребленный внутри безымянной функции void() приводит не только к выходу из нее, но к выходу из первой функции по стеку, не имеющей в определении модификатора passthrough (или defmacro - привет Lisp-ерам ). На функцию for вешаем модификатор passthrough, остальные функции по умолчанию его не имеют. Таким образом, у нас return будет работать корректно, как и раньше.
Мне, пожалуй, парочку!
G>Интересная задачка из серии занимательный С++ , не находишь?
Здравствуйте, Трурль, Вы писали:
Т>Здравствуйте, Gaperton, Вы писали:
G>>Эксцепшены будем ловить внутри for. Остался return — это жесткач. Вводим дополнительное правило — return, употребленный внутри безымянной функции void() приводит не только к выходу из нее, но к выходу из первой функции по стеку, не имеющей в определении модификатора passthrough (или defmacro - привет Lisp-ерам ). На функцию for вешаем модификатор passthrough, остальные функции по умолчанию его не имеют. Таким образом, у нас return будет работать корректно, как и раньше.
Т>Мне, пожалуй, парочку!
G>>Интересная задачка из серии занимательный С++ , не находишь? Т>
Думаете это все? Да это только начало. Домашнее задание: расширить С++ до такой степени, штобы в терминах языка можно было бы определить конструкцию switch . И пусть живые завидую мертвым.
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Влад, это не просчет, это разница в подходе. Я, например, последнее время "болею" идеей, как бы можно было бы ввести в язык такую "фичу", чтоб прямо в терминах языка можно было бы for и while прозрачно выразить, оставив в языке только if и goto. Это, собственно, не для for и while нужно, а для того, чтоб алгоритмы, подобные тому, что в STL, были бы в языке first class citizens. А в C#, напротив, foreach в язык "воткнули". Вот такая вот разница.
У меня в forth-компилере "ref" не только for и while, но и + и — и прочие "stdcall" и "uses" написаны на этом же языке.
D>К вопросу добавляем необходимость ключевого слова volatile.
Ну, если ты на C++ с аппаратурой не работаешь, то вряд ли тебе потребуется volatile.
Тут был здоровенный флэйм про мультипоточность и volatile: volatile у переменной класса
Здравствуйте, Gaperton, Вы писали:
G>>>Эксцепшены будем ловить внутри for. Остался return — это жесткач. Вводим дополнительное правило — return, употребленный внутри безымянной функции void() приводит не только к выходу из нее, но к выходу из первой функции по стеку, не имеющей в определении модификатора passthrough (или defmacro - привет Lisp-ерам ). На функцию for вешаем модификатор passthrough, остальные функции по умолчанию его не имеют. Таким образом, у нас return будет работать корректно, как и раньше.
Т>>Мне, пожалуй, парочку!
G>>>Интересная задачка из серии занимательный С++ , не находишь? Т>>
G>Думаете это все? Да это только начало. Домашнее задание: расширить С++ до такой степени, штобы в терминах языка можно было бы определить конструкцию switch . И пусть живые завидую мертвым.
Жестко. Так что там Гринспун про 10 правило говорил?
AndrewVK,
>>> Невозможность модификации контейнера это не ограничение foreach, а ограничение итераторов стандартных контейнеров.
> ПК> Ну и что? Речь шла о том, что foreach подходит не везде. Это был один из примеров. Собственно, суть сводится к тому, что алгоритмов, связанных с обходом контейнера много, и foreach — один из них, далеко не всегда наиболее подходящий.
> Следи за губами — foreach это не алгоритм.
1) Не хами, и не хамим будешь... 2) Все зависит от выбранной терминологии.
> Алгоритм находится внутри итератора.
В моей терминологии внутри итератора находится описание порядка обхода, а foreach — алгоритм, сводящийся к перебору элементов в порядке, заданном итератором. Скажем, remove_if — тоже алгоритм, тоже работающий, основываясь на порядке обхода, заданном итератором, но, очевидно, отличающийся от for_each. Если тебе удобнее называть for_each, find, find_first_if, search, equal, remove_if, copy_if, replace_if, reverse и т.п. другим словом, замени "алгоритм" на него в моих предыдущих сообщениях и ниже.
> При наличии итератора, котjрый умеет определенным образом обрабатывать удаления? удалять внутри foreach можно.
Еще раз. Возможность удаления внутри foreach не является центральным аргументом, это просто пример, тем не менее остающийся валидным: для стандартных итераторов удаление работать не будет. Аргументом является наличие других, отличных от foreach, алгоритмов (в понимании, описанном выше), которые во многих случаях подходят намного лучше.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Gaperton,
> ПК> Я, например, последнее время "болею" идеей, как бы можно было бы ввести в язык такую "фичу", чтоб прямо в терминах языка можно было бы for и while прозрачно выразить, оставив в языке только if и goto. Это, собственно, не для for и while нужно, а для того, чтоб алгоритмы, подобные тому, что в STL, были бы в языке first class citizens. А в C#, напротив, foreach в язык "воткнули". Вот такая вот разница.
> Хе-хе . Если "язык" — это С++, то все довольно просто. Поехали: <...>
Да, что-то в более-менее похожем духе. Не обязательно в C++, но интересно. Сами for, while и т.п. переопределять, естественно, не предполагается. Хочется полноценной поддержки "алгоритмов", подобных STL algorithms. Естественно, для этого нужны лямбда-выражения и замыкания. На самом деле, далеко не обязательно, чтоб выглядело буквально как for и while, но хочется, чтоб количество лишних телодвижений у пользователя было минимальным. Также маячит идея, что (по мотивам некоторых функциональных языков) можно более удачно, чем шаблоны C++, ввести поддержку обобщенного программирования. В частности, в определенных случаях очень полезным может оказаться откладывание определения типа выражения, что в C++ не поддерживается. Например:
enum A { a };
enum B { b };
void foo(A);
void foo(B);
template< class T, class F >
void bar( T t, F f )
{
f( t );
}
void g()
{
bar( a, foo );
}
В C++ будет неоднозначность, т.к. выбрать тип foo в точке вызова bar не удастся. Хочется, чтоб можно было bar вызвать с "недовыведенным" типом. Есть устойчивое ощущение, что введение "прозрачных" замыканий лямбда-выражений зависит от возможности отложенного выведения типов.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Паш, ты уж извини, но ты начинашь очень сильно утомлять своей бессмысленной софистикой и докапыванием до слов.
Паш, вникай в смысл, а резводи бодягу по каждому поводу.
АВК тебе сказал, что невозможность удаления элементов внутри оператора foreach языка C# обусловена не ограничениями этого оператора, а ограничениями итераторов стандартных контерйнеров.
Все! Точка! И не нужно разводить софистику на терминологическую тематику.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
VladD2,
> Паш, вникай в смысл, а резводи бодягу по каждому поводу.
Чего и вам желаю...
> АВК тебе сказал, что невозможность удаления элементов внутри оператора foreach языка C# обусловена не ограничениями этого оператора, а ограничениями итераторов стандартных контерйнеров.
Вот я именно по этому поводу уже третий раз и отвечаю: это на смысл исходного сообщения
, на которое отвечал AVK, вообще никак не влияет.
> Все! Точка! И не нужно разводить софистику на терминологическую тематику.
Вот о чем я и говорю в который раз: как называть foreach алгоритмом или валенком — не важно; важно, что таких "валенков" много, а поддержка в языке присутствует только для одного из них.
P.S. На этом я, пожалуй, закончу повторять одно и то же: кому захочется "вникнуть в смысл, а не развести бодягу по каждому поводу" — перечитает...
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Вот о чем я и говорю в который раз: как называть foreach алгоритмом или валенком — не важно;
Лучше называть его оператором. Будет всем спокойнее.
ПК> важно, что таких "валенков" много, а поддержка в языке присутствует только для одного из них.
В языке пристствует поддержка ООП. Его более чем хватает для создания большинства паттернов. Те что используются особо часто или те которые от интеграции с языком могут выиграть интегрируются в язык.
foreach — это еще фигня. Вот во многих современных языках встравивают такие фишки как list comprehension (конструктор списков). Если подходить к таким фичам с твоей позиции, то это просто таки надругательство над языком, так как в язык уже не просто встраивается паттерн. В его уже встраиваеются целые процедуры. Но вот работа со списками с их использованием становится почти декларативной.
В Руби, например, встроен такой "простенький" паттерн как continuations. Тоже надругательство.
Но вот что странно! Ты постоянно плюешся на подобные вещи в Шарпе и даже словом не объмолвишся о других языках. От чего такая изберательность? Давай обсудим Руби или Хаскель.
ПК>P.S. На этом я, пожалуй, закончу повторять одно и то же: кому захочется "вникнуть в смысл, а не развести бодягу по каждому поводу" — перечитает...
Ты это перед сном повторяй. Можно перед зеркалом. А то пожалуй кроме тебя все уже это запомнили. А тоы вот все пыташся докапаться до слова и уйти в другой лес.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Gaperton,
>> ПК> Я, например, последнее время "болею" идеей, как бы можно было бы ввести в язык такую "фичу", чтоб прямо в терминах языка можно было бы for и while прозрачно выразить, оставив в языке только if и goto. Это, собственно, не для for и while нужно, а для того, чтоб алгоритмы, подобные тому, что в STL, были бы в языке first class citizens. А в C#, напротив, foreach в язык "воткнули". Вот такая вот разница.
>> Хе-хе . Если "язык" — это С++, то все довольно просто. Поехали: <...>
ПК>Да, что-то в более-менее похожем духе. Не обязательно в C++, но интересно. Сами for, while и т.п. переопределять, естественно, не предполагается. Хочется полноценной поддержки "алгоритмов", подобных STL algorithms. Естественно, для этого нужны лямбда-выражения и замыкания. На самом деле, далеко не обязательно, чтоб выглядело буквально как for и while, но хочется, чтоб количество лишних телодвижений у пользователя было минимальным.
Что мне не нравится в большинстве предложений, это то, что лямбда функции определяются внутри (). Поэтому получается, что {} скобки появляются внутри () скобок, и это очень неестественно для C-подобных языков. Так уже сделано в Java и C#. Выглядит это плохо, нечитабильно.
В то же время, для родных конструкций типа for блок {} идёт сразу за конструкцией, а не находится внутри неё. Поэтому, хочется, чтобы алгоритмы выглядели как можно ближе к родным конструкциям. Например:
vector<int> v;
for_each(v.begin, v.end())
{
// lambda function
}
Здесь {} блок идёт сразу за вызовом функции вместо полагающейся точки с запятой.
Такая запись выглядет гораздо приличнее, естественнее и ближе к тому, чему мы все привыкли. Осталось только подумать, что нужно сделать, чтобы запись типа такой стала реальностью.
Понятно, что нужно где-то определять сигнатуру лямбда функции, потому что функция, которая не принимает никаких параметров и не возвращает значение, не имеет никакого применения для стандартных алгоритмов (а ведь именно это и является целью: упрощение использования стандартных алгоритмов).
Неплохо выглядет предложение использовать ; внутри параметров к функции. Например:
int b;
vector<int> v;
for_each(v.begin(), v.end(); void(int a))
{
cout << a + b << endl;
}
Здесь void(int a) — это сигнатура функции, определённой сразу за for_each().
Далее следует вопрос, а как организовать замыкания? Наиболее логично, как мне кажется, представлять замыкания как функтор, который имеет operator() и содержит ссылки на локальный контекст.
В такой модели, код приведенный выше, преобразуется во что-то вроде следующего:
struct __closure {
int & b_;
__closure(int & b) : b_(b) {}
void operator()(int a) {
cout << a << b_ << endl;
}
};
int b;
vector<int> v;
for_each(v.begin(), v.end(), __closure(b));
Здравствуйте, Павел Кузнецов, Вы писали:
>> Следи за губами — foreach это не алгоритм.
ПК>1) Не хами, и не хамим будешь...
Я не хамлю. Просто намекаю на то что игнорировать слова собеседника не очень конструктивно.
ПК>2) Все зависит от выбранной терминологии.
Ага, это любимый твой конек — если чувствуешь что не прав перевести спор на обсуждение термингологии. Обсуждать терминологию я не буду. Принципиально.
>> При наличии итератора, котjрый умеет определенным образом обрабатывать удаления? удалять внутри foreach можно.
ПК>Еще раз. Возможность удаления внутри foreach не является центральным аргументом, это просто пример, тем не менее остающийся валидным: для стандартных итераторов удаление работать не будет.
А казалось бы, при чему тут конструкция языка foreach?
ПК> Аргументом является наличие других, отличных от foreach, алгоритмов (в понимании, описанном выше), которые во многих случаях подходят намного лучше.
foreach это не алгоритм, это синтаксический сахар. Пока ты этого не поймешь, дальнейшее обсмуждение бессмысленно.
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Gaperton,
>> ПК> Я, например, последнее время "болею" идеей, как бы можно было бы ввести в язык такую "фичу", чтоб прямо в терминах языка можно было бы for и while прозрачно выразить, оставив в языке только if и goto. Это, собственно, не для for и while нужно, а для того, чтоб алгоритмы, подобные тому, что в STL, были бы в языке first class citizens. А в C#, напротив, foreach в язык "воткнули". Вот такая вот разница.
>> Хе-хе . Если "язык" — это С++, то все довольно просто. Поехали: <...>
ПК>Да, что-то в более-менее похожем духе. Не обязательно в C++, но интересно. Сами for, while и т.п. переопределять, естественно, не предполагается. Хочется полноценной поддержки "алгоритмов", подобных STL algorithms. Естественно, для этого нужны лямбда-выражения и замыкания. На самом деле, далеко не обязательно, чтоб выглядело буквально как for и while, но хочется, чтоб количество лишних телодвижений у пользователя было минимальным.
Базис языка (Си) очень плохо для этого подходит, ИМХО, что я и старался показать. Для достижения нормального результата (простой красивый язык) придется сказать С++ досвиданья.
ПК>Также маячит идея, что (по мотивам некоторых функциональных языков) можно более удачно, чем шаблоны C++, ввести поддержку обобщенного программирования.
Лучшее, что придумано на эту тему на данный момент — система типов Хиндли-Милнера, или нечто похожее. Примеры — система типов OCaml, Nemerle.
ПК>В частности, в определенных случаях очень полезным может оказаться откладывание определения типа выражения, что в C++ не поддерживается. Например: ПК>
ПК>enum A { a };
ПК>enum B { b };
ПК>void foo(A);
ПК>void foo(B);
ПК>template< class T, class F >
ПК>void bar( T t, F f )
ПК>{
ПК> f( t );
ПК>}
ПК>void g()
ПК>{
ПК> bar( a, foo );
ПК>}
ПК>
ПК>В C++ будет неоднозначность, т.к. выбрать тип foo в точке вызова bar не удастся. Хочется, чтоб можно было bar вызвать с "недовыведенным" типом. Есть устойчивое ощущение, что введение "прозрачных" замыканий лямбда-выражений зависит от возможности отложенного выведения типов.
Здесь проблема в другом. Система не знает детали устройства типа F, в то время как в языке с системой типов Хиндли-Милнера эти детали ей известны. Из контекста bar однозначно выводится, что тип F — это функция (функтор), отображающая T в нечто, чего компилятор С++ делать просто не умеет — система типов не позволяет .
В случае системы типов Хиндли-Милнера компилятор однозначно определит сигнатуру полиморфной функции без помощи программиста.
Здравствуйте, AndrewVK, Вы писали:
AVK>Невозможность модификации контейнера это не ограничение foreach, а ограничение итераторов стандартных контейнеров.
Для справки: В C# foreach не предоставляет доступ к текущей позиции итератора. так же, как и к самому итератору. И, даже если снять ограничение на изменение итерируемых контейноров — от кривости foreach это не спасет (так и представляю себе "красоту" реализации удаления элемента из середины связянного списка на базе foreach).
Хотя, не спорю — можно и головой гвозди забивать.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
alexeiz,
> Что мне не нравится в большинстве предложений, это то, что лямбда функции определяются внутри (). Поэтому получается, что {} скобки появляются внутри () скобок, и это очень неестественно для C-подобных языков. Так уже сделано в Java и C#. Выглядит это плохо, нечитабильно. В то же время, для родных конструкций типа for блок {} идёт сразу за конструкцией, а не находится внутри неё. Поэтому, хочется, чтобы алгоритмы выглядели как можно ближе к родным конструкциям.
Мои "мучения" начались именно с этого (плюс ниже), но сейчас к данному неудобству я отношусь уже намного спокойнее, и даже готов смириться, больше "напрягает" второе.
> Понятно, что нужно где-то определять сигнатуру лямбда функции, потому что функция, которая не принимает никаких параметров и не возвращает значение, не имеет никакого применения для стандартных алгоритмов (а ведь именно это и является целью: упрощение использования стандартных алгоритмов).
Требование явного задания сигнатуры мне кажется не менее неудачным, как и {} внутри (): тому же for никакая сигнатура для "вызова" {} не нужна. Есть устойчивое ощущение, что если применить для определения "сигнатуры" содержимого {} вывод типов, подобно некоторым функциональным языкам, то можно добиться полной аналогии с встроенными операторами. Причем, что интересно, в какой-то момент в обсуждении auto мелькали идеи возможности его использования для вывода результатов функций. Впрочем, за явное задание сигнатуры тоже есть свои аргументы...
> Далее следует вопрос, а как организовать замыкания? Наиболее логично, как мне кажется, представлять замыкания как функтор, который имеет operator() и содержит ссылки на локальный контекст.
Такая модель будет адекватно работать только в случае, если время жизни замыкания не выходит за пределы времени жизни соответствующего контекста. Впрочем, для 99%, имхо, такое ограничение проблемой не является. Но хочется, оставшийся 1% тоже можно поддержать, пусть и несколько более сложным в использовании способом. Все время маячит идея какого-то синтаксиса для создания замыканий в динамической памяти, и перекладыванию ответственности за время жизни на программиста. Нужно только как-то согласовать, что в этом случае контекст таки должен копироваться. Для того, чтоб не было путаницы, скорее всего, более правильным было бы введение различного синтаксиса для "ссылочного" и "копирующего" использования переменных из окружающих блоков в лямбда-выражениях.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен