Здравствуйте, eao197, Вы писали:
E>>>Ну да бог с ним. Меня ты не переубедил, а правду пускай историки ищут.
ЗХ>>Вот спасибо. Вот уж спасибочки...
E>Может тебе, как историку, интересна будет приведенная вот здесь схема эволюции языков (взято отсюда: http://www.levenez.com/lang/ только уж я не знаю, насколько этому источнику можно доверять, хотя на него и O'Reilly ссылается: http://www.oreilly.com/pub/a/oreilly/news/languageposter_0504.html).
Лежит она у меня давно...
E>Так вот получается, что Java произошла от Oak, который вобрал в себя: Ada 83, Objective C, C++, Cedar, Smalltalk-80, Scheme. Не хилая солянка, однако (но синтаксис-то C++ный ). E>А у C# было всего три прародителя: Deplhi 5, C++, Java. (Но ведь и Java имеет в родителях C++, так что у C# с C++ довольно тесные родственные связи ).
Моя имха — по схеме можно приблизительно ориентироваться, но доверять ей в каждом конкретном случае (для каждого конкретного языка) нужно с большой осторожностью.
Ладно, выскажусь в философском смысле немножко.
- А-а! Вы историк? — с большим облегчением и уважением спросил Берлиоз.
— Я — историк, — подтвердил ученый и добавил ни к селу ни к городу: — Сегодня вечером на Патриарших прудах будет интересная история!
Итак, поразмыслим немножко о "происхождении одного языка от других". Что, вообще, можно подразумевать, говоря "язык Б произошел от языка А"? 1. Синтаксис Б расширяет синтаксис А
По этому признаку, большинство современных мейнстрим-языков "произошли" от C.
Такое "происхождение", чаще всего, можно однозначно доказать.
Ценность такой концепции "происхождения" близка к 0.
2. Семантика Б расширяет семантику А
Именно это зачастую подразумевается.
Тут все далеко не так однозначно: во-первых, в некотором смысле тяжело провести разграничение между синтаксисом и семантикой; во-вторых, тяжело провести разграничения между "Б расширяет семантику А" и "Б изменяет сематику А".
По этому признаку, скажем (имхо!), Java и C# не только не являются наследниками C++, но в некотором роде не являются и наследниками C.
3. Б использует некоторое концепции, [впервые] появившиеся в А
Именно это подразумевается в вышеприведенной схеме и во фразе "Oak, который вобрал в себя: Ada 83, Objective C, C++, Cedar, Smalltalk-80, Scheme". Можно ли назвать это "происхождением" — вопрос, в общем, довольно спорный. Который, к тому же, требует определения "первого появления" концепции.
4. Б в некотором роде наследует "дух" А
Тоже очень сложный вопрос. Хотя и часто используется в быту. Когда Гослинг говорит
: "Для разработчика, язык выглядел совершенно как C++. Но в душе Java взяла очень много от Smalltalk, Lisp и Pascal." — он, скорее всего, имеет в виду это.
Итого. Вариант (1) — относительно легко доказуем при полной бесполезности; (2) — доказуем с оговорками; (3) и (4) — во-первых, непонятно, можно ли это считать "происхождением", во-вторых, практически невозможно доказать. Дело в том, что откуда в языке Б взялась концепция X — может знать только создатель языка. При этом:
* он может забыть, что натолкнуло его на некоторую идею
* он может сознательно врать (версия, которой придерживаются сторонники происхождения Java от Oberon)
В конце концов, в процессе создания языка создатель перелопачивает горы литературы, просматривает сотни языков, проводит тысячи обсуждений — в результате у него в голове формируется некоторая "общая идея". И если эта идея сама по себе не включает "пусть мой язык будет наследником такого-то" (Страуструп, сознательно создающий C++ как наследника C), то, имхо, определенно говорить о происхождении одного языка от другого мы не имеем права.
Andrei N.Sobchuck wrote:
> C>То есть? В Эрланге используются именно явные сообщения, для которых > C>можно даже задавать грамматику (делать диалоги). Ну и еще Эрланг > C>является чисто функциональным (в нем нет деструктивного присваивания > C>вообще). > Процессы обмениваются сообщениями. Внутри процессов — функциональщина. > Вроде бы так.
Ну да, причем сообщения — это неизменяемые (immutable) данные.
VD>int[] array = {1,2,3,2,4,5,7,6,7,2};
VD>var y = from x in array
VD> where x < 7
VD> group x by x into z
VD> orderby z.Key
VD> select new { Value = z.Key, Встерчается = z.Group.Count() };
VD>foreach (var varue in y)
VD> Console.WriteLine(varue);
VD>
Понял, что меня в этом варианте смущает Слишком много "новых ключевых слов". По сути, это отдельный DSL внутри C#. Т.е. воспринимается, как "посреди программы перешли на другой язык".
Внимание! Я не утверждаю, что это плохо. Скорее, инерция моего сознания мешает мне назначить это решение "красивым".
При этом, кстати, вот этот вариант мне "гармоничнее" смотрится.
var y = array.Where(x => x < 7).GroupBy(x => x).OrderBy(z => z.Key)
.Select(z => new { Value = z.Key, Встерчается = z.Group.Count() });
Кстати, попробовал предположить, как могла бы выглядет библиотека, делающая то же самое на C++:
//тут предполагается, что select вернет объект, у которого будут нужные методы
/*тип?*/ y = select(array, _1 < 7).groupBy(_1).orderBy(_1.key).generate( std::make_pair(_1.key, _1.group.count) );
Какие проблемы мы тут имеем?
* Очень мешает отсутствие авто-вывода типа.
* Обращение к _1.key и т.п. требует либо "жирности" интерфейса _1, либо суррогатов вроде
member(_1, /*тип?*/::key);
//или
_1.method("key");
//или, наконец, учитывая, что мы знаем, что это методы типа, который вернул groupBy:
...groupBy(_1).orderBy(_group.key).generate( std::make_pair(_group.key, _group.group.count) );
Здравствуйте, Cyberax, Вы писали:
>> Процессы обмениваются сообщениями. Внутри процессов — функциональщина. >> Вроде бы так.
C>Ну да, причем сообщения — это неизменяемые (immutable) данные.
Вот процессы я и обозвал макроуровнем, в противовес функциональщине на "микро"-уровне. Прошу прощения, что не обяснил мысль.
Здравствуйте, Cyberax, Вы писали:
>> И по объему не больше, и читабельность выше (нет птьичих расширений >> вида if_[]), и понятность (для новичков, изучающих C++), и мощность >> (т.е. внутри lambda любые возможности языка можно использовать, в том >> числе и вложенные lambda).
C>А не получится так сделать, да еще чтобы нормально сочеталось с C>остальными функциями. Например, какой у лямбда-функции будет тип? Какое C>время жизни?
C>Я пока не видел нормальной реализации лямбд в языках с ручным C>управлением памятью
for_each( begin(a), end(a),
void lambda( const int & x, map_t & m = occur )
{ if( x < 7 ) m[ x ]++; }
);
Имхо, есть привязки к локальному контексту внутри тела lambda нет, то компилятор может развернуть этот код так:
class lambda_impl
{
private :
map_t & m_m;
void body( const int & x, map_t & m )
{ if( x < 7 ) m[ x ]++; }
public :
lambda_impl( map_t & m ) : m_m( m ) {}
void operator()( const int & x ) { body( x, m_m ); }
};
for_each( begin(a), end(a), lambda_impl() );
Собственно, получается тот же самый вариант с функтором, как у меня, только обвязочный код функтора генерирует компилятор. Не вижу здесь проблем с временем жизни подобной лямбды.
C>На самом деле, стоит все-таки выучить boost::lambda — писать с ней C>такие простые вещи получается быстрее.
Ну блин, проблема с Boost-ом не в том, что бы его выучить. С этим-то как раз проблем нет.
Проблема в том, что Boost не стандарт. Хорошо, что на многих платформах он есть. Да только если придется перейти на платформу, где его нет, то нестандартность Boost-а вылезет боком. Мне время от времени приходится с такой платформой иметь дело: HP NonStop.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, alexeiz, Вы писали:
E>>Попробуй написать так там, где нет Boost-а.
A>Там, где нет Boost'а, нужно его сделать.
Мне?
Нет, мне своих собственных самоделок хватает. А базовые вещи, я считаю, мне должен компилятор обеспечивать.
A>С правильной комбинацией инклюдов — работает. end — часть Boost.Range, перегружено для разных контейнеров, в том числе и для массивов.
Понятно. Действительно, есть такое дело.
E>>Вот за эти птичьи поддиалекты C++ мне и не нравится нынешнее направление развития C++. Что такое if_ -- это другой вариант if-а? А откуда берется переменная _1? А могу ли я обратиться к _2? А почему после if_ составной оператор записывается не в фигурных скобках, а в квадратных? А bind(&val_t::first, _1) -- это, надо полагать, завуалированный вызов _1.first? Определенно, с задачей скрыть смысл написанного bind хорошо справился E>>
A>_1.first не работает, так как точка не перегружается. Вообще-то по идее там должно быть _1->first. Но это тоже не работает. _2 там есть, и т.д. вплоть до десяти параметров. if_ пришел из Spirit'а. В последствии был адаптирован для Boost.Lambda. Квадратные скобки, потому что это всё суть expression templates.
Ты сейчас мне объяснил то, что я и сам понимаю. Только:
— во-первых, что будет, если в приведенном примере я обращусь к _2?
— во-вторых, как я сказал, это очень ограниченное подмножество C++. Да еще в не стандартном синтаксисе.
A>Чтобы использовать Boost.Bind или Boost.Lambda не нужно 10 летнего опыта.
Да, по поводу 10 летнего опыта, это я ошибся. Как раз мне мой опыт подсказывает, что такие велосипеды хорошо выглядят при первом знакомстве, а потом ничего кроме головной боли при сопровождении не вызывают. А обучать молодых таким техникам вообще, вероятно, та еще задача. Сначала попробуй объяснить что такое указатель, чем указатель от ссылки отличается, затем почему лучше не использовать голые указатели, затем рассказать про функторы, затем про Boost.Bind & Boost.Lambda, затем о том, где Boost.Lambda лучше не использовать, затем о том, что внутри Boost.Lambda лучше не вызывать...
Лично я после этого становлюсь сторонником "Keep It Simple Stupid". Но, видимо, это только мои проблемы
A>Фиг его знает, какие lambda предложат в C++0x. Но то, что ты написал, это небольшой перебор. Можно и короче. Типы повыводить и прочее.
Попробуй предложить свой вариант. Мне интересно, как могут выглядеть lambd-ы в C++ с выводом типов аргументов и возвращаемого значения.
E>>Только чего-то мне подсказывает, что я могу подобных расширений C++ и не дождаться. А пока буду ждать, для меня безопаснее по старинке. С рукописными объектами-функторами. Опыт показывает, что при сопровождении (в том числе и не мной) это оправдывается.
A>Пример с Boost.Lambda великолепно читается. Я, конечно, понимаю, что сперва такая запись может вызвать ступор. Но как только свыкнешся, что подобное возможно, в последствии не вызывает труда читать такой код, даже если ты не знаешь конкретно, что он делает. Код достаточно самодокументирующий.
Ага, привыкаешь, и начинаешь считать костыли нормой. Вот это мне и не нравится.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
eao197 wrote:
> Имхо, есть привязки к локальному контексту внутри тела lambda нет, то > компилятор может развернуть этот код так: > >class lambda_impl > { > private : > map_t & m_m; > > void body( const int & x, map_t & m ) > { if( x < 7 ) m[ x ]++; } > > public : > lambda_impl( map_t & m ) : m_m( m ) {} > void operator()( const int & x ) { body( x, m_m ); } > }; > >for_each( begin(a), end(a), lambda_impl() ); > > Собственно, получается тот же самый вариант с функтором, как у меня, > только обвязочный код функтора генерирует компилятор. Не вижу здесь > проблем с временем жизни подобной лямбды.
Я зато вижу проблемы: скорее всего в теле лямбда-функции нужен будет
доступ к членам родительского класса. Вот тут-то и начинаются проблемы —
лямбда же является функтором, который спокойно передается по значению и
может пережить родительский класс. Значит каким-то образом нужно
прикручивать политики владения к ней.
Они над этим работают
> Хорошо, что на многих платформах он есть. Да только если придется > перейти на платформу, где его нет, то нестандартность Boost-а вылезет > боком. Мне время от времени приходится с такой платформой иметь дело: > HP NonStop.
Ну так как лямбды — это синтаксический сахар, то и переписать его особых
проблем нет. Хотя это и неприятно
Здравствуйте, Cyberax, Вы писали:
>> Собственно, получается тот же самый вариант с функтором, как у меня, >> только обвязочный код функтора генерирует компилятор. Не вижу здесь >> проблем с временем жизни подобной лямбды.
C>Я зато вижу проблемы: скорее всего в теле лямбда-функции нужен будет C>доступ к членам родительского класса.
О каком родительском классе идет речь?
C> Вот тут-то и начинаются проблемы — C>лямбда же является функтором, который спокойно передается по значению и C>может пережить родительский класс. Значит каким-то образом нужно C>прикручивать политики владения к ней.
Зачем? Если lambda -- это функтор, то не него распространяются такие же правила жизни, как и на обычные объекты.
>> Проблема в том, что Boost не стандарт.
C>Они над этим работают
Если Boost.Lambda станет стандартом, то уже точно буду думать о том, куда уходить с C++
>> Хорошо, что на многих платформах он есть. Да только если придется >> перейти на платформу, где его нет, то нестандартность Boost-а вылезет >> боком. Мне время от времени приходится с такой платформой иметь дело: >> HP NonStop.
C>Ну так как лямбды — это синтаксический сахар, то и переписать его особых C>проблем нет. Хотя это и неприятно
Ну вот не нравится мне переписывать и перетестировать работающий код. Уж лучше сразу писать на "C с классами", чем затем к такому виду приводить "красивый" код на шаблонах.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
eao197 wrote:
> C>Я зато вижу проблемы: скорее всего в теле лямбда-функции нужен будет > C>доступ к членам родительского класса. > О каком родительском классе идет речь?
Класс, из метода которого создается лямбда.
> C> Вот тут-то и начинаются проблемы — > C>лямбда же является функтором, который спокойно передается по значению и > C>может пережить родительский класс. Значит каким-то образом нужно > C>прикручивать политики владения к ней. > Зачем? Если lambda -- это функтор, то не него распространяются такие > же правила жизни, как и на обычные объекты.
Так ведь сама по себе лямбда не особо интересна — важна возможность
замыкания на создавший класс. А тут-то и появляются всякие интересности.
>>> Проблема в том, что Boost не стандарт. > C>Они над этим работают > Если Boost.Lambda станет стандартом, то уже точно буду думать о том, > куда уходить с C++
Boost.Bind точно станет — он уже есть в TR1.
> C>Ну так как лямбды — это синтаксический сахар, то и переписать его > особых > C>проблем нет. Хотя это и неприятно > Ну вот не нравится мне переписывать и перетестировать работающий код. > Уж лучше сразу писать на "C с классами", чем затем к такому виду > приводить "красивый" код на шаблонах.
Просто когда выйдет C++09 старых компиляторов скорее всего не останется
Точнее, там где они останутся — новый С++ не нужен будет.
Здравствуйте, Cyberax, Вы писали:
>> C>Я зато вижу проблемы: скорее всего в теле лямбда-функции нужен будет >> C>доступ к членам родительского класса. >> О каком родительском классе идет речь?
C>Класс, из метода которого создается лямбда.
>> Зачем? Если lambda -- это функтор, то не него распространяются такие >> же правила жизни, как и на обычные объекты.
C>Так ведь сама по себе лямбда не особо интересна — важна возможность C>замыкания на создавший класс. А тут-то и появляются всякие интересности.
Похоже, что я подхожу к lambda гораздо проще. Возможно даже, что я под ламбдами понимаю чего-нибудь другое.
По-моему, попытка привязки функторов в C++ к каким-то контекстам -- это не правильно. Такие фокусы еще прокатывают в управлямых языках. Но, например, в Ruby это приводит к некоторым тонким моментам. В C++ же лично меня напрягает огромное количество синтаксического мусора, который я вынужден создавать для описания собственного функтора (жирным выделен код, который действительно имеет для меня значение):
class my_functor_t : public std::unary_function< param_type, result_type >
{
public :
result_type operator()( argument_type a ) { /* Мой код */ }
};
и это если мне не нужно связывание функтора с какими-то внешними объектами, то оверхед еще больше увеличивается:
class my_another_functor_t : public std::unary_function< param_type, result_type >
{
binded_object_type m_binded_object;other_object_type m_other_object;public :
my_another_functor_t(
binded_object_type binded_object,
other_object_type other_object )
: m_binded_object( binded_object )
, m_other_object_type( other_object )
{}
result_type operator()( argument_type a ) { /* Мой код */ }
};
Вот такое положение вещей на современном уровне развития уже не нормально. Ведь можно же более просто дать компилятору понять, что мне необходимо:
result_type lambda(
param_type a,
binded_object_type binded_object = ...,
other_object_type other_object = ... )
{
/* Мой код */
}
А все остальные обертки компилятор пусть генерит сам.
И не нужны мне никакие неявные контексты. Если я создаю лямбду в каком-то классе, то я сам могу дать лямбде доступ к нужным частям моего класса:
class my_class_t
{
some_list_t m_list;
some_map_t m_map;
some_complex_data_t m_data;
...
void some_method()
{
some_list_t updated_list;
std::for_each( m_list.begin(), m_list.end(),
void lambda( some_list_t::value_type a,
some_list_t & receiver = updated_list,
some_map_t & map = m_map,
const some_complex_data_t & data = m_data )
{
/* Мой код, который использует m_map, m_data (через ссылки map и data). */
}
);
m_list.swap( updated_list );
}
};
>> C>Ну так как лямбды — это синтаксический сахар, то и переписать его >> особых >> C>проблем нет. Хотя это и неприятно >> Ну вот не нравится мне переписывать и перетестировать работающий код. >> Уж лучше сразу писать на "C с классами", чем затем к такому виду >> приводить "красивый" код на шаблонах.
C>Просто когда выйдет C++09 старых компиляторов скорее всего не останется C> Точнее, там где они останутся — новый С++ не нужен будет.
Очень печальная для языка программирования точка зрения, имхо
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Cyberax,
>> (т.е. внутри lambda любые возможности языка можно использовать, в том >> числе и вложенные lambda).
> А не получится так сделать, да еще чтобы нормально сочеталось с > остальными функциями. Например, какой у лямбда-функции будет тип?
Какой-нибудь "внутренний" класс-тип.
> Какое время жизни?
Например, ограниченное временем жизни наиболее короткоживущего значения, используемого в ней.
> Я пока не видел нормальной реализации лямбд в языках с ручным управлением памятью
+1, но в последнее время появляются интересные мысли.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
alexeiz,
> Фиг его знает, какие lambda предложат в C++0x. <...>
К сожалению, скорее всего, никакие: deadline для языковых предложений уже позади, а предложений lambda так и не было видно. Теперь надежда на разработчиков компиляторов...
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Моя имха — по схеме можно приблизительно ориентироваться, но доверять ей в каждом конкретном случае (для каждого конкретного языка) нужно с большой осторожностью.
А что, находил ляпы?
ЗХ>Ладно, выскажусь в философском смысле немножко.
Я позволю себе не согласится с одним из пунктов.
ЗХ>Итак, поразмыслим немножко о "происхождении одного языка от других". Что, вообще, можно подразумевать, говоря "язык Б произошел от языка А"? ЗХ>1. Синтаксис Б расширяет синтаксис А ЗХ>По этому признаку, большинство современных мейнстрим-языков "произошли" от C. ЗХ>Такое "происхождение", чаще всего, можно однозначно доказать. ЗХ>Ценность такой концепции "происхождения" близка к 0.
Вот мне так не кажется.
Как показывают жаркие споры о "синтаксическом оверхеде" и о том, "что Java -- это испорченный С-ным синтаксисом Oberon" (сюда же можно отнести и то, что большая часть критики Oberon-а сводится к тому, что КЛЮЧЕВЫЕ СЛОВА нужно ЗАПИСЫВАТЬ в верхнем РЕГИСТРЕ ), вопрос первичности синтаксиса очень важен.
Возьмем два языка, близких по возможностям, но совершенно разных по синтаксису: Паскаль и C. По мне, синтаксическая разница между ними состоит не в том, что присваивание в Паскале -- это ":=", а в C -- "=". И не в том, что составной оператор в Паскале ограничивается begin/end, а в C через {}. Самая большая разница в Паскале -- это разбиение программы на секции: секция объявления типов, секция объявления констант, секция объявления переменных. Или еще одно: считать ли присваивание выражением (имеющим значение, как в C) или же оператором (более точно -- statement, не имеющим значения), а дальше -- возможность/невозможность использования присваивания в логических выражениях (злополучный if(a=b)). Из-за этих синтаксических различий структура программы на Паскале отличается от структуры программы на C. А вот это уже намного существеннее. Это уже отражает мировозрение авторов языка.
Наверное, более правильно было бы утверждать, что первичнее те идеи, которые авторы закладывали в Паскаль и С, и то мироощущение, которое у них было на момент разработки языков. А уже из этого вышел тот или иной синтаксис. Но в том-то и дело, что мироощущение и пр. философские понятия эфимерны, подвержены изменению со временем, а синтаксис -- он и есть объективная реальность.
Настолько объективная, что заимствованные из других языков идеи переносятся в новый язык не один в один, а с адаптацией к выбранному в качестве базиса синтаксису.
Попытаюсь привести аналогию: пусть все идеи, вошедшие в какой-то язык -- это как мебель, которую нужно перевезти с одной квартиры на другую. И мы можем использовать для этого либо грузовик с полностью открытой платформой, бортовой, фургон или даже рефрижератор, лесовоз или самосвал. Из каких-то соображений мы выбираем тип грузовика, а затем уже прикидываем, как бы туда получе и безопаснее нашу мебель загрузить. Так вот синтаксис -- это и есть тот сам тип грузовика. И оказалось, что в лице C, а затем и C++, индустрия получила наиболее универсальный тип синтаксиса.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
ЗХ>>Моя имха — по схеме можно приблизительно ориентироваться, но доверять ей в каждом конкретном случае (для каждого конкретного языка) нужно с большой осторожностью.
E>А что, находил ляпы?
Ну, что значит "ляпы", если само понятие "такой-то язык произошел от такого-то" является убийственно нечетким?
ЗХ>>1. Синтаксис Б расширяет синтаксис А ЗХ>>По этому признаку, большинство современных мейнстрим-языков "произошли" от C. ЗХ>>Такое "происхождение", чаще всего, можно однозначно доказать. ЗХ>>Ценность такой концепции "происхождения" близка к 0.
E>Вот мне так не кажется.
E>Как показывают жаркие споры о "синтаксическом оверхеде" и о том, "что Java -- это испорченный С-ным синтаксисом Oberon" (сюда же можно отнести и то, что большая часть критики Oberon-а сводится к тому, что КЛЮЧЕВЫЕ СЛОВА нужно ЗАПИСЫВАТЬ в верхнем РЕГИСТРЕ ), вопрос первичности синтаксиса очень важен.
E>Возьмем два языка, близких по возможностям, но совершенно разных по синтаксису: Паскаль и C. По мне, синтаксическая разница между ними состоит не в том [...] Из-за этих синтаксических различий структура программы на Паскале отличается от структуры программы на C. А вот это уже намного существеннее. Это уже отражает мировозрение авторов языка.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Понял, что меня в этом варианте смущает Слишком много "новых ключевых слов". По сути, это отдельный DSL внутри C#. Т.е.
Вообще-то это всего лишь заспросы внутри языка. В Хаскеле почему-то аналогичная вещь никого не смущает. Ну, а синтаксис знаком почти всем, так как очень похож на SQL.
ЗХ> воспринимается, как "посреди программы перешли на другой язык". ЗХ>Внимание! Я не утверждаю, что это плохо. Скорее, инерция моего сознания мешает мне назначить это решение "красивым".
Просто ты привык к низкоуровневым языкам.
ЗХ>При этом, кстати, вот этот вариант мне "гармоничнее" смотрится. ЗХ>
ЗХ>var y = array.Where(x => x < 7).GroupBy(x => x).OrderBy(z => z.Key)
ЗХ> .Select(z => new { Value = z.Key, Встерчается = z.Group.Count() });
ЗХ>
Ага, даже короче. Но вот читать его все же сложнее. Замыленно как-то. Слишком много лишних деталей. Куча лямбд, точек, скобок...
ЗХ>Кстати, попробовал предположить, как могла бы выглядет библиотека, делающая то же самое на C++: ЗХ>
ЗХ>//тут предполагается, что select вернет объект, у которого будут нужные методы
ЗХ>/*тип?*/ y = select(array, _1 < 7).groupBy(_1).orderBy(_1.key).generate( std::make_pair(_1.key, _1.group.count) );
ЗХ>
Гы. Это мечта. Причем пока что не сбыточная. Как минимум лямбд в С++ нет и в лучшем случае прийдется пользоваться разными буст::бинд. При этом количество мусора выростит до непреличия, а понятность уменьшится. К тому же все эти _1 понимать куда хуже чем именованные параметры.
ЗХ>Какие проблемы мы тут имеем? ЗХ>* Очень мешает отсутствие авто-вывода типа.
Еще бы. И не только оно. Еще мешает отсуствие анонимных типов (tuples, кортежей), расширяющих методов (ведь все эти Where, GroupBy и т.п. не родные методы коллекций, их подключили извне).
ЗХ>* Обращение к _1.key и т.п. требует либо "жирности" интерфейса _1, либо суррогатов вроде ЗХ>
ЗХ>member(_1, /*тип?*/::key);
ЗХ>//или
ЗХ>_1.method("key");
ЗХ>//или, наконец, учитывая, что мы знаем, что это методы типа, который вернул groupBy:
ЗХ>...groupBy(_1).orderBy(_group.key).generate( std::make_pair(_group.key, _group.group.count) );
ЗХ>
Забавно, что в C# 3.0 все работает на базе приметивнейшого IEnumerable<T>. Вот, например, реализации некоторых расширяющих методов:
public static IEnumerable<T> Where<T>(
this IEnumerable<T> source,
Func<T, bool> predicate)
{
foreach (T element in source)
if (predicate(element))
yield return element;
}
public static OrderedSequence<T> OrderBy<T, K>(
this IEnumerable<T> source,
Func<T, K> keySelector)
{
return new OrderedSequence<T, K>(source, null, keySelector, null, false);
}
public static IEnumerable<Grouping<K, E>> GroupBy<T, K, E>(
this IEnumerable<T> source,
Func<T, K> keySelector,
Func<T, E> elemSelector,
IEqualityComparer<K> comparer)
{
Dictionary<K, List<E>> dict = new Dictionary<K, List<E>>(comparer);
foreach (T element in source)
{
K key = keySelector(element);
E elem = elemSelector(element);
List<E> list;
if (!dict.TryGetValue(key, out list))
{
list = new List<E>();
dict.Add(key, list);
}
list.Add(elem);
}
foreach (KeyValuePair<K, List<E>> pair in dict)
yield return new Grouping<K, E>(pair.Key, pair.Value);
}
public static IEnumerable<S> Select<T, S>(
this IEnumerable<T> source,
Func<T, S> selector)
{
foreach (T element in source)
yield return selector(element);
}
this у первого параметра как раз и указывает, что этот метод расширяет другой класс, а не является простым статическим методом. Этот метод можно применять "через точку" к любому наследнику типа указанного в параметре. А так как IEnumerable<T> — это интерфейс который реализуется всеми коллекциями дотнета начиная от массива и заканчивая связанным списком, то эти функции применимы практически к любой коллекции.
В общем, в язык все сильнее встраивают функцкиональный стиль и на его основе реализуют абстракции более высокого порядка.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Зверёк Харьковский, Вы писали:
ЗХ>Ну, что значит "ляпы", если само понятие "такой-то язык произошел от такого-то" является убийственно нечетким?
Странно, но мне так не кажется. Даже если у языка и не было непосредственных родителей (как C у C++, Паскаля у Modula и Ada), то все равно были языки, которые оказали на него самое большое влияние. Вот если стрелочки на той схеме рассматривать как "влияние", то "убийственной нечеткости" уже не будет.
E>>Возьмем два языка, близких по возможностям, но совершенно разных по синтаксису: Паскаль и C. По мне, синтаксическая разница между ними состоит не в том [...] Из-за этих синтаксических различий структура программы на Паскале отличается от структуры программы на C. А вот это уже намного существеннее. Это уже отражает мировозрение авторов языка.
ЗХ>И называется семантикой
Которая отражается в грамматике языка
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, VladD2, Вы писали:
E>>Влад, так все-таки, на какой версии C# сделаны приведенные тобой примеры? Мне показалось, что на 3.0, а не на 2.0.
VD>А 3.0 — это только компилятор. Сборки у него формата 2.0. Так что это только синтаксический сахар. От рантайма поддержка не нужна.
Т.е. получается, что в скором времени стоит ожидать выхода C# 3.0. И что скомпилированные им программы будут работать на втором .Net. И когда Mono полностью реализует поддержку 2.0, то скомпилированный MS компилятором C# 3.0 программы будут работать там, где есть Mono?
Если так, то круто!
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
ЗХ>>Ну, что значит "ляпы", если само понятие "такой-то язык произошел от такого-то" является убийственно нечетким?
E>Странно, но мне так не кажется. Даже если у языка и не было непосредственных родителей (как C у C++, Паскаля у Modula и Ada), то все равно были языки, которые оказали на него самое большое влияние. Вот если стрелочки на той схеме рассматривать как "влияние", то "убийственной нечеткости" уже не будет.
E>>>Возьмем два языка, близких по возможностям, но совершенно разных по синтаксису: Паскаль и C. По мне, синтаксическая разница между ними состоит не в том [...] Из-за этих синтаксических различий структура программы на Паскале отличается от структуры программы на C. А вот это уже намного существеннее. Это уже отражает мировозрение авторов языка.
ЗХ>>И называется семантикой
E>Которая отражается в грамматике языка
Вестимо. А чего ты хотел? Тем не менее, "является ли присваивание statement или expression" — вопрос семантики, а не синтаксиса. Я так думаю.
Здравствуйте, Зверёк Харьковский, Вы писали:
E>>Странно, но мне так не кажется. Даже если у языка и не было непосредственных родителей (как C у C++, Паскаля у Modula и Ada), то все равно были языки, которые оказали на него самое большое влияние. Вот если стрелочки на той схеме рассматривать как "влияние", то "убийственной нечеткости" уже не будет.
ЗХ>Мда Значит, напрасно я распинался
Нет, не напрасно. Я же возражаю только против одного из твоих пунктов
Ну и кроме того, не расчитываешь же ты, что у твоих читателей мнение будет на 100% совпадать с твоим.
E>>>>Возьмем два языка, близких по возможностям, но совершенно разных по синтаксису: Паскаль и C. По мне, синтаксическая разница между ними состоит не в том [...] Из-за этих синтаксических различий структура программы на Паскале отличается от структуры программы на C. А вот это уже намного существеннее. Это уже отражает мировозрение авторов языка.
ЗХ>>>И называется семантикой
E>>Которая отражается в грамматике языка
ЗХ>Вестимо. А чего ты хотел? Тем не менее, "является ли присваивание statement или expression" — вопрос семантики, а не синтаксиса. Я так думаю.
Семантики, семантики.
Только вот в чем фокус. Думаю, что грамматика таких языков, как Oberon/Modula/Pascal просто не допускают применения := в выражениях. Поэтому там даже семантической проверки для таких случаев делать не нужно. А вот C-подобных языках можно использовать = в выражениях. Поэтому конструкции if(a=b) отслеживаются не на этапе синтактического анализа, на на этапе семантического (при проверке типа выражения). Т.е. некоторые грамматики просто сильно снижают нагрузку на семантический анализ.
Вот это я имел в виду.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.