Здравствуйте, _vovin, Вы писали:
_>Как обычно — реактивность мышления не является объективным фактором. Поэтому скипаем.
Реативность... турбо-газо-генераторность... Всприятие оно и есть восприятие. Не даром Смолток со всеми его идеями силит в одном месте долго и безспросветно.
Язык должен быть удобен и понятен максимальному числу людей, или это уже не язык, а шифрограмма.
VD>>А вот так это будет выглядеть на C# 3.0: VD>>
Что значит "минус"? Статический полиморфизм есть. Есть варианты для float, double, int и можно еще прикрутить.
VD>>Или "вариации на тему": VD>>
VD>>var sum = array.Fold((fold, second) => fold + second);
VD>>
_>А что выдаст для одного элемента или пустого списка?
Исключение. Кроме того есть перегруженный метод где начальное значение можно задать вручную (вместе с его типом). Ну, и опять же это не встроенная возможность. Это методы которые мы можем создавать сами. Захочу — создам и "инжект". Только не захачу — бо уж больно бессмысленное название. Скорее создам — Accumulate.
VD>>Ну, и самое простое... C# 1.0: VD>>
VD>>int sum = 0;
VD>>foreach (int elem in array)
VD>> sum += elem;
VD>>
_>Это эквивалент не для #inject:into: а для вот этого
_>
_>sum := 0.
_>array do: [:elem | sum := sum + elem].
_>
Сори, в Смолтоке я не знаток. Могу понять не правильно. Лучше описывать задачу на естественном языке или на чем-то более традиционном.
Да и неочем тут говорить. Функции расширения создаются программистом самим. Причем для любого класса. Замена блока кода является лямбда. В ней только параметры описываются, а не подразумеваются.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Dyoma, Вы писали:
D>Вообще-то метод называется inject:into: D>collection inject: initialValue into: block D>Читается так "коллекция вставь начальное значение в блок, вычисляющий следующее"
Угу. Вот русская фраза, объясняющая смысл операции:
"Примени вот этот блок к каждому элементу коллекции с вот таким начальным значением"
Вот импортный вариант:
"For each collection item perform this block with this as initial value"
Покажите мне, где здесь Inject? Приведите мне пример фразы на хорошем английском языке, в которой есть слова inject и into, и которая внятно отражает суть выполняемого действия? Твой пример еще менее понятен, чем смоллтоковая программа.
Просто потому, что вставка чего-то в блок у меня никак не ассоциируется с передачей аргумента.
Авторы этой терминологии явно пересмотрели Звездных войн. "Впрысни ноль в деяние с суммой и аргументом к сложенью их сводящееся".
Бред. Замазывание основного смысла действия — применения блока к каждому элементу. Поставка начального значения — вторична. Не всем алгоритмам оно вообще нужно.
На сишарпе все читается очень близко к нормальному английскому:
for each a in array increment sum by a.
foreach(int a in array) sum += a;
Это понятно без высшего образования. Стиль, конечно же, телеграфный — полностью отвечая потребностям программиста. Мы пишем не письмо Татьяны к Онегину, а максимально краткую инструкцию. "Шлите апельсины бочками".
Я бы назвал метод как-нибудь типа perform: initWith:. D>А теперь премся над C++: D>[code] D>class MyClass {...}
D>x = new MyClass(); // Я что в этой строке новый класс создаю??? А почему мне все говорят, что объект?
Потому, что ты хреново называешь классы.
DeviceContext dc = new ScreenContext();
Нормально читается? Вот и нефиг совать в имя класса слово Class. Это тавтология.
D>Фишка в том что на C-образных языках такой метод — не естественное (читай ракообразное решение). Как там в C#3.0 — не знаю... тебе виднее, что можно в лямбду запихать. В Smalltalk можно в блок запихать все, в том числе и выход из метода в котором это блок создан:
... << RSDN@Home 1.1.4 stable rev. 510>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, _vovin, Вы писали:
_>Это эквивалент не для #inject:into: а для вот этого _>
_>sum := 0.
_>array do: [:elem | sum := sum + elem].
_>
Это понятно. Но раз мы решили не ограничиваться встроенными средствами, давайте сделаем на шарпе полный эквивалент:
public delegate R Collector<R, T>(R current, T item);
public static R Collect<R, T>(IEnumerable<T> collection, Collector<R, T> collector, R initialValue)
{
R current = initialValue;
foreach (T item in collection)
current = collector(current, item);
return current;
}
... << RSDN@Home 1.1.4 stable rev. 510>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, eao197, Вы писали:
E>А вот на счет статически типизируемого -- это уже твоя идея. Я лишь сказал про универсальный язык, который может быть либо интерпритируемым, либо компилируемым в байт-код, в промежуточный код или в нейтив-код. Руби как раз универсальный язык общего назначения.
Нет. Руби не является GPL (языком общего назначения). Это скриптовый язык. GPL подразумевает, что хотя бы гипотетически на нем можно написать все от драйверов и ядра ОС, до финансового приложения. Руби же принципиально интерпритируем и не годится для некоторых задач.
E> На котором, имхо, DSL можно плодить.
Возможно.
E> Тебе не нравится программировать на интерпритируемом и динамически типизируемом языке -- да ради бога, не программируй. Жди, когда M$ сделает для тебя C# 3.0.
Да, вроде как и 2.0 хватает. Но ДСЛ на Шарпе конечно делать не просто.
E>>>Готов? Лично я не готов.
VD>>Я готов. Излагай...
E>Чего изглагать? Я же написал -- не готов. Пока.
Ждем.
E>1. На C++ у нас создан собственный фреймворк для агентно-ориентированного программирования. С помощью этого фреймфорка написаны все C++ приложения. Их нужно сопровождать и развивать. Поэтому я продолжаю использовать C++.
Сделай обертку для Руби. Или перепиши все на Руби. В чем проблема то?
E>2. С языком Ruby я познакомился в августе прошлого года. Сделал на Ruby один проект (тот самый mxx_ru). Затем эпизодически использовал Ruby для написания маленьких вспомогательных скриптов. И только в последние два-три месяца стал серьезно расматривать Ruby в качестве дополнения к C++.
Вот я тебя и спрашваю. Почему дополнения?
Мне, например, Шарп заменяет и Руби, так как на нем программировать так же эффективно, и С++ так как я могу создавать код стольк же быстрый как и на С++. При этом я не жертвую ни статической типизацией, ни удобством работы. Плюс я имею отличные средства разработки (комплит ворд, рефакторин, отладчик, профайлеры и т.п.). Ты же все время рассказывашь о крутизне Руби, но пишеш реальный код на С++.
E> Отсюда два следствия:
E>2.1. У меня еще нет достаточного опыта в создании сложных/больших систем на Ruby.
Но его достаточно чтобы пропагандировать Руби? Странно...
E>2.2. Для Ruby нужно создать средства, которые позволили бы интегрировать Ruby с нашим агентным фреймворком.
Зачем? Завершите использование С++. Оформите весь код в виде компонетов доступных в Руби и дальше пишите все только на нем.
E>А у Ruby пока есть одна самая важная сложность: динамическая типизация.
О! Вот к этому я тебя и подводил. Ты боишся создавать серьезные проекты на динамически типизированных языках. Кстати, у Руби не только эта пробелма. У него еще некоторые проблемы в безопастности вроде необязательности декларации переменных и методов, а так же вроде того что миксины могут обращаться к неопределенным сущьностям. Хотя все это следствие динамической типизации.
E> Из-за нее вести разработку следует не так, как я привык -- нужно существенно увеличивать объем тестирования.
А не боишся утопнуть в расползающихся несоотвествиях? Ведь с ростом объемов модулей они будут вылезать все чаще, и все непредсказуемее.
E>Но главной проблемой у Ruby является отношение окружающих к подобным языкам, которое ты здесь очень ясно обозначил.
Дык, я не не говорю о том "почему я не буду писать серьезный код на Руби". Я справишваю почему ты это не делашь.
E> Если помнишь, полгода назад мы с тобой в топике Типизация
спорили с _vovin про C++, Smalltalk, строгую, статическую и динамическую типизацию. Тогда я был ортодоксальным сторонником статической типизации. Но тот разговор не прошел даром. После него мое отношение к динамически типизируемым языкам вообще, и Ruby в частности, изменилось на противоположное. Зато теперь мне самому приходится сталкиваться с неприятием динамически типизируемых языков.
Хм... Это тебя колбасит.
Я вот не привык так резко менять убеждения. Хотя я и раньше не был полностью убежден в том, что динамика — это зло. Мне кажется у всего есть свои пложительные свойства. По этому я и хочу иметь язык повзволяющий если что "подинамить".
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
E>>Mixins
VD>Слишком уж много проблем в данной реализации.
VD>Тут делается ставка на полной интерпретируемости языка. А это и не эффективно, и опасно.
Зато интересно и увлекательно
... The introduction of Ruby to the programming world has astounded developers with its ability to simply make programming fun again...
(Ruby Developer's Guide)
VD>Для того же Шарпа такое решение не подходит. Язык ориентирован на статическое связывание и контроль. А такое решение с этими понятиями не совместимо.
А при чем тут Шарп
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, VladD2, Вы писали:
VD>Нет. Руби не является GPL (языком общего назначения). Это скриптовый язык. GPL подразумевает, что хотя бы гипотетически на нем можно написать все от драйверов и ядра ОС, до финансового приложения. Руби же принципиально интерпритируем и не годится для некоторых задач.
Для любых языков есть задачи, для которых эти языки не годятся. И для C++, и для Java, и для C#. Ruby здесь не исключение.
VD>>>Я готов. Излагай...
E>>Чего изглагать? Я же написал -- не готов. Пока.
VD>Ждем.
Ok. Как только, так сразу. Даже если опыт будет отрицательным.
E>>1. На C++ у нас создан собственный фреймворк для агентно-ориентированного программирования. С помощью этого фреймфорка написаны все C++ приложения. Их нужно сопровождать и развивать. Поэтому я продолжаю использовать C++.
VD>Сделай обертку для Руби. Или перепиши все на Руби. В чем проблема то?
Взять и сделать. Как всегда.
E>>2. С языком Ruby я познакомился в августе прошлого года. Сделал на Ruby один проект (тот самый mxx_ru). Затем эпизодически использовал Ruby для написания маленьких вспомогательных скриптов. И только в последние два-три месяца стал серьезно расматривать Ruby в качестве дополнения к C++.
VD>Вот я тебя и спрашваю. Почему дополнения?
Потому что сейчас просто нет возможности выбросить все существующие наработки на C++ и переписать все на Ruby. Более того, это вообще не имеет смысла. Поэтому начатые на C++ проекты будут продолжатся на C++, а то, что можно будет делать на Ruby будет делаться на Ruby.
VD>Мне, например, Шарп заменяет и Руби, так как на нем программировать так же эффективно, и С++ так как я могу создавать код стольк же быстрый как и на С++. При этом я не жертвую ни статической типизацией, ни удобством работы. Плюс я имею отличные средства разработки (комплит ворд, рефакторин, отладчик, профайлеры и т.п.). Ты же все время рассказывашь о крутизне Руби, но пишеш реальный код на С++.
"Жертвуя статической типизацией"... Звучит-то как.
Как выясняется, не такое это уж и достижение, которым приходится жертвовать. Да и отладчики с профайлерами в Ruby есть изначально.
Вот ты мне скажи, появился C# 1.0, ты что, сразу на нем production системы писать стал? Или же поприглядывался, потестировал, пару-тройку пробных проектов сделал, а потом уже с C++ соскочил?
, Gaperton дает хороший рецепт внедрения в производство новой технологии:
Для текущего проекта смена языка реализации нереальна, это и так всем понятно. Для новых проектов это вполне может иметь смысл, почему нет? Это первое, и второе — кто-то заставляет сразу писать на незнакомой платформе критичный проект? Боже упаси. Стратегия перехода на новую платформу предполагает существенно более сложный сценарий, и это, как я думал, не является предметом дискуссии.
Но если говорить о смене платформы — то и это вполне возможно. Только начинать надо с микропрототипов для proof of the concept. А потом (если все в порядке) с маленьких некритичных проектов. Потом (если итоги их внедрения и экстплуатации положительны), внедрять новую платформу шире, с учетом накопленного опыта. Только осторожно, никакой спешки, риски надо контроллировать.
Вот чему-то подобному я и пытаюсь следовать. Сейчас я пишу на Ruby вспомогательные скрипты для упрощения обслуживания новой версии одного из наших комплексов. Они встанут на боевое дежурство вместе с самим комплексом.
Следующий шаг, возможно, будет замена конфигурационных файлов Ruby скриптами. Т.е. запускается скрипт, в котором заданы все конфигурационные параметры, а он уже раскручивает C++ модули.
Далее, возможно, будет реализация на Ruby новых протоколов на основе SOAP.
Паралелльно с этим на Ruby должна быть реализована наша агентная технология.
Это то, что сейчас есть в моих планах. А там время покажет.
E>> Отсюда два следствия:
E>>2.1. У меня еще нет достаточного опыта в создании сложных/больших систем на Ruby.
VD>Но его достаточно чтобы пропагандировать Руби? Странно...
Ну что делать, переполняют меня хорошие впечатления от Ruby. Делюсь ими с окружающими. Потом буду делиться набитыми шишками
E>>2.2. Для Ruby нужно создать средства, которые позволили бы интегрировать Ruby с нашим агентным фреймворком.
VD>Зачем? Завершите использование С++. Оформите весь код в виде компонетов доступных в Руби и дальше пишите все только на нем.
Что-то подобное я и хочу сделать. Только не совсем завершить использование C++, а сделать так, чтобы можно было писать либо на C++, либо на Ruby и объединять получившиеся модули.
E>>А у Ruby пока есть одна самая важная сложность: динамическая типизация.
VD>О! Вот к этому я тебя и подводил. Ты боишся создавать серьезные проекты на динамически типизированных языках.
Опыта пока не было. Сейчас приобретаю.
E>> Из-за нее вести разработку следует не так, как я привык -- нужно существенно увеличивать объем тестирования.
VD>А не боишся утопнуть в расползающихся несоотвествиях? Ведь с ростом объемов модулей они будут вылезать все чаще, и все непредсказуемее.
А у меня рецепт есть: вместо того, чтобы создавать большие модули, лучше создавать больше мелких модулей. А результирующий комплекс создавать из них как из кирпичиков или кубиков конструктора.
Совершенно серьезно. Интерфейсы модулей отслеживать гораздо проще, чем внутренности каждого модуля. Кроме того, такие решения лучше масштабируются (отдельные модули можно разносить по разным узлам кластера и балансировать нагрузку между ними) и оказываются более надежными (падение одного модуля не влечет за собой падение остальных).
E>>Но главной проблемой у Ruby является отношение окружающих к подобным языкам, которое ты здесь очень ясно обозначил.
VD>Дык, я не не говорю о том "почему я не буду писать серьезный код на Руби".
Здесь не столько твое отношение к Ruby имелось в виду. Вообще, если я сейчас начну своим коллегам предлагать перейти на Ruby, то ничего из этого не выйдет. Просто потому, что про языки, вроде Ruby или Python-а очень мало кто знает. Т.е. названия-то многие слышали. Кто-то даже знает, что в Python структуризация отступами делается. А вот реальные возможности этих языков, я думаю, представляют себе не многие. И переубедить из можно только предьявив работающий код и многократно повторив, какой же Ruby замечательный язык.
VD> Я справишваю почему ты это не делашь.
Я сейчас не пишу mission critial код на Ruby по двум причинам:
1. Я не считаю, что у меня есть для этого достаточный опыт работы на Ruby. Mxx_ru и десяток-другой вспомогательных административных скриптов я считаю недостаточно.
2. Нет возножности гладко интегрировать написанные на Ruby модули с написанными на C++ модулями (созданными на нашем агентно-ориентированном фреймворке).
Для того, чтобы устранить первую причину я сейчас использую Ruby для решения вспомогательных, не столь важных, задач. С одной стороны, это дает опыт. С другой -- провал в них не будет иметь фатальных последствий.
Для устранения второй причины, кроме опыта и хорошего знания Ruby, потребует еще и несколько идей. А рождение идей -- процесс не быстрый, не легкий, и не детерминированный (по крайней мере у меня).
А вообще, код на Ruby я пишу. Каждую неделю чего-нибудь да делаю на нем. Так что двигаюсь по тихоньку.
E>> Если помнишь, полгода назад мы с тобой в топике Типизация
спорили с _vovin про C++, Smalltalk, строгую, статическую и динамическую типизацию. Тогда я был ортодоксальным сторонником статической типизации. Но тот разговор не прошел даром. После него мое отношение к динамически типизируемым языкам вообще, и Ruby в частности, изменилось на противоположное. Зато теперь мне самому приходится сталкиваться с неприятием динамически типизируемых языков.
VD>Хм... Это тебя колбасит.
VD>Я вот не привык так резко менять убеждения.
Ну ничего себе быстро -- полгода прошло. Как говорится, я не тормоз, я медленный газ.
VD> Хотя я и раньше не был полностью убежден в том, что динамика — это зло. Мне кажется у всего есть свои пложительные свойства. По этому я и хочу иметь язык повзволяющий если что "подинамить".
На самом деле меня привлекает в Ruby несколько черт:
— возможность создавать лаконичные DSL. То, для чего в C++ громоздятся страничные макросы и трехэтажные шаблоны, на Ruby делается всего несколькими строками;
— мне не очень нравится то, что происходит вокруг моего любимого языка С++. С одной стороны, острая нехватка библиотек. Например, для поддержки HTTP, SOAP, баз данных. Вот придется по SOAP или XML-RPC C++ приложение с Java-приложением подружить, и начинается долгое курение над каким-нибудь gSOAP-ом. С другой стороны, в C++ сейчас какой-то сумашедший крен в сторону обобщенного и метапрограммирования, да не просто так, а на навороченных шаблонах. Иной раз глянешь на фрагменты с использованием boost-а (которые MaximE или Кодт в форумах по C++ иногда приводят) и думаешь: "Мама дорогая!" Ну усложняется все, имхо, неимоверно. Может быть, будь я помоложе чуть-чуть, с большим запасом энтузиазма, и мне все это казалось бы нормальным. Но сейчас это уже overkill. И если какой-нибудь Boost.MultiIndex или Boost.Bind еще можно осилить, то Boost.Spirit или Boost.MPL уже явно не для меня. Или вот такие навороты: Lisp на C++
. Ну не так жить нужно. А с третьей стороны, слишком медлено С++ в современных условиях развивается. Слишком долго C++0x рождается, и слишком медлено C++ компиляторы поддержку хотя бы C++98 внедряют. Да еще M$ воду мутит -- то managed C++, то C++/CLI. Теперь вот еще одна очередная идея: concurrent c++
. Забабахало. В Ruby всей этой мути нет. Одна реализация. Одно мощное community. Развитая стандартная библиотека. Увеличивающаяся популярность. А динамическая типизация позволяет обобщенно программировать почти как на плюсовых шаблонах. Поэтому и есть надежда, что всякие новомодные и тормознутые по своей природе SOAP-ы да XML-RPC с SQL-ем взятые можно клепать на Ruby, а важные по быстродействию и ресурсоемкости части спокойно можно на нормальном C++ делать.
— в Ruby работающую программу без выгрузки модифицировать можно. Это интересно.
И все это при том, что программы на Ruby реально очень компактными получаются. Самому удивительно.
Ну а динамическая природа Ruby и его интерпритируемость... Не привычно, по началу. Ну что же, у каждого свои недостатки. Да и недостатки ли? То, что для кого-то проблема, для другого -- возможность. Так что будем из динамической типизации выжимать все лучшее.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Интересное мнение. Итак, мы имеем: процедурный (не ОО) язык С, произошедший от него ОО язык С++, ОО языки Java/C# (появившиеся гораздо позже C++). При этом утверждается, что Java и C# напрямую производные от C, а не от C++. Вероятно, ты считаешь это логичным. Я -- нет.
Ну, у меня в отличии от тебя для этого есть обоснование. Если бы C# произошел от С++, то он должен был бы быть или совместим с С++ снизу в верх, или хотя бы быть сильно на него похожим, для чего опять же пришлось бы взять все что было и возможно отбросить некоторые плохие (по мнению создателей Шарпа) идеи.
C# несомненно повзаимствовал у С++ некоторые идеи. Более того некоторые кострукции перекочевали без изменений. Однако этого явно не достаточно чтобы сказать что Шарп является развитем С++. В конце концов в Шарпе есть немало пересечений и с совсем, казалось бы, непохожими языками вроде Оберона. Что же Шарп произошел и от Оберона, и от С++? Внебрачный сын? Так не бывает.
Шарп просто вобрал в себя идеи из раных языков. Так идею "все является объектом", принципы наследования и многе другое он позаимствовал у Смолтока. Болшую часть базового синтаксиса у С. А у С++ он взял только ключевые слова class, struct и т.п. Причем даже использует их совершенно по другому. Так в С++ struct == class у которого по умоланию члены яляются публичными. А в шарпе struct это вэлью-тип, и по умолчанию все поля в нем отнюдь не публичны. Так с кого содран struct? С "С" или с "С++"? А черт его знает. Наличие методов вроде как заимствование из С++, но сама идея структур уж явно С-шная.
Оператор new вроде как взят из С++, но были ведь языки и до С++ у которых был такой же оператор. Страуструп сам говорил, что заимствовал ОО-идеи у других языков.
В общем, если начать проводить детальное сравнение, то окажется, что за исключением схожести клюевых слов у C++ и C# других совпадений почти нет.
Идеологически C# больше похож на Дельфи. Ну, а то что C# похож на С++ лексически не мудренно. Именно этого и добивались.
VD>>А отсутствие конструкций для обобщенного программирования (шаблонов то ведь нет и не будет в этих языках) скорее объясняется как раз тем, что создатели языка пытались скопировать технику полиморфизма не у С++, а скорее у Смолтока.
E>Я думаю, что разработчики Java/C# могли бы здесь дать более точную версию. E>Имхо, в первой версии Java не было шаблонов потому, что шаблоны только-только появились в C++ и еще не были такой важной частью языка, какой они являются сейчас.
Только что? Ява вышла в 95-ом (или даже в 96-ом) году. Шаблоны в С++ использовались начиная с начала девяностых. Так что уже 5 лет как шаблоны были. А уж C# вышел в 2002-ом. Что же ему помешало лучше скопировать предка? Не уж, то времени нехватило?
E> Поэтому авторы Java просто не оценили вовремя всего потенциала шаблонов.
Напомню. Смолток, Лисп, Окамл, Руби и множество других языков появившихся как за долго до С++, так и сильно после обладают куда более развитыми средствами полиморфизма и при этом не имеют шаблонов.
Для полиморфизма шаблоны не обязательны. А вот проблемы которые создают шаблоны более очевидны. Шаблоны — это статический полиморфизм. Он мешает языку порождать динамическиие решения. Ява и Шарп проектировались как динамические языки. Однако кроме того они были еще и статически типизированными. По этому для создания динамики исповедовали копонентную парадигму. Статический полиморфизм препятствует копонентности, по этому видимо был выбран путь ориентации на динамический полиморфизм. Но тут, думаю, авторы этих языков допустили одну ошибку. Динамический полиморфизм изумителен в динамически типизированных языках, так как динамическая типизация скрывает некоторые проблемы. Проблемы подобного рода замечательно видны на примере коллекций (последовательностей, списков... называй их как хочешь). Конечно моно создать коллекцию для любого типа элементв, но получается сизифов труд. Другой выход сделать все объектами приводимыми к некоторому общему базовому классу (кстати, в яве это небыло реализовно доконца, там влэлю-типы не приводились к объектам автоматически и их приходилось помещать в специально создаваемые объекты, так сказать ручной боксинг). Далее оставалось только сделать коллекцию для этого базового класса и проблема вроде как решена. Решера, то решена, но не очень хорошо. Поместить объект в коллекцию труда не представляет. Но при вынимании приходитмя приводить тип объекта. Динамически типизированные языки такой проблемы не имет, так как во-перых, не имет понятия типизированная сылка. Вместо этого тип объекта и так известен по ссылке. Во-вторых же, динамические языки автоматически преобрзуют типы перед применением их в операциях, чтобы пользователь не напрягался декларирую повсеместно типы. Другими словами в статически типизированные языки, дабы не терять приемущества статической типизации, было решено не вводить атвоматические приведения типов к наследникам. Таким образом хранение объектов в обобщенном виде приводило к необходимости втавлять явные приведения типов. Это с одной стороны делало языки частично динамически типизируемыми (не позволяло использвать статическую типизацию везеде), а с другой приводило к засорению кода.
Для статически типизированного языка проблема решается только введением статического полиморфизма.
Итак появилась дилемма. Статический полиморфизм испортит компонентность языка. Но без него получается излишний динамизм да еще и пусор в коде.
Дилема и была решена введением дженериков. Дженирики это полу-статический, полу-динамический полиморфизм. Декларируется он статически, но проверяется и поддерживается на стадии джит/преджит-копмиляции. У С++ такой возможности, честно говоря, небыло. У него просто отсуствовала такая стадия. Но у него отсутствовала и потребность быть копонентным. Такая потребность появилась только в девяностых, но к тому времени С++ уже сформировался.
E> Ведь очень серьезный толчок массовому использованию шаблонов дала библиотека STL, появившаяся (если не ошибаюсь) где-то в 93-м. Как раз тогда, когда основной дизайн Java уже был оформлен.
Это не првда. И СТЛ появился раноше. И шаблоны использовались независимо от СТЛ. По крайней мере к тому времени когда появилась Ява я во всю писал КОМ-объекты с испльзованием ATL.
Ну, и опять таки. Плевать на Яву. Мы ведем речь о C#. Он появился в 2002 году. Так что твоя гипотиза о незхватке времени явно некатит. Успели же они пол языка переработать? Ввели свойства, foreach, индексаторы, перечисления, делегаты, события, полиморфизм массивов, препроцессор (да, фиг все упомнишь!), а такую важную часть С++ добавить забыли? Дудки!
E>На Дельфи не программировал. Не берусь судить.
А я программировал. И бурусь утверждать, что C# намного ближе к Дельфи чем С++. Это доказывает и довольно простое освоение Шарпа дельфистами. Хотя и Дельфи не является пробразом C#-а. Кстати, на этом форуме на полном серьезе обсуждалась мысль о том, что в Шарпе все содрано с Дельфи. И я задолбался сражаться доказывая, что это идея бредовая.
VD>> С++ это все же сначало С, потом шаблоны, и уж потом ООП, а можно и безнего.
E>И это говорит человек, который утверждает, что хорошо знал C++! (... и эти люди запрещают мне ковыряться в носу! (анекдот)).
И сейчас знаю не тау уж плохо.
E>До того, как в C++ появились нормальные шаблоны, в С++ прежде всего было ООП, а затем уже C.
До того как в С++ появились шаблоны в С++ появился С! И этим все сказано.
А время появления фич не так важно. Да ООП появился раньше. Но на сегодня есть маньяки (считающие себя соврешенно вменяемыми и имеющими наглость оскорблять других крича что им все кроме него промыли мозги клизьмами) отровенно наезжающие на те самые завоемвания ООП которые Страуструп ввел в С++ "сначала". И я его понимаю. Если наплевать на дизайн и драться за каждый байт производительности, то можно обойтись из без классического ООП. Все же статический полиморфизм тоже полиморфизм, и исползуя его в купе с приемами вроде прведения к классам потомкам в теле базового класса можно добиваться (и другим подобным "красивым" приемам) очень многого жертвуя, павда, простотой и понятностью.
И это не еденичный случай! Это уже традиция. На сегодня в С++ именно что сначала С, потом шаблоны, а помто уже ООП. Причем можно даже без ООП вообще. С то с шаблонами есть же?
E> Имхо, множество бед C++ происходит из-за того, что его пытаются использовать как "улучшенный C", в лучшем случае, как "С с классами".
Расскажи это любителям пооскорблять собеседников бегающих рядом с клизмами.
А мне не надо. Я выбрал язык в котором программировать как в С или С с классами практически невозможно. Ну, или хотя бы затрахаешся.
E>Пора бы уже осознать, что C++ -- это другой язык, нежели C.
С++ язык в котором без проблем можно программировать по разному. Можно в С поиграть. Можно в ООП побаловаться. А можно даже под Лисп покасить. Причем именно С в нем удается лучше всего. Отличный, надо сказать, С плучился! А вот ООП уже получается натянутый. И все из-за экономии. А экономить ведь так хочется! Ну, нет по умолчанию виртуальных деструкторов. Ну, и что (казалось бы)? А на деле выходит, что программист думает — "Ага! Если я его добавлю, то объект распухнет на 4 или даже больше байт! А это тормоза и неэффективное испоьзование ресурсов коструктора!" — лучше бы он этих слов и не знал — "Ткк зачем мне это? Ну, его на фиг этот вирутальный деструктор. Вот появятся виртуальные функци тогда добавлю. А пока извернусь...". Но виртуальных функций тоже не появляется (ну, ты понял по каким причинам). И начинаем мы вместо ООП на С++ делать эмуляцию ООП на С с классами. Далее все это удобряется изрядной порцией шаблонов больше похожих на шифровку и...
E> Он просто вырос из C и долгое время поддерживал совместимость с C.
Хм... Не долгое время, а все время.
E> Поэтому и программировать на нем нужно, не так, как на C. Тогда и не придется в очередной раз жалиться, какой же он дырявый, сколько в нем проблем, и сколько лично ты шышек набил, ступая по его граблям.
"жалиться" отом какой он дрянной приходится даже если ты программируешь на нем в традициях ООП без ремарок. Уж больно много граблей разложено на этом пути. Но то что С "жалеет всех живых" внутри С++ просто таки подталкивает к не ООП-прграммированию. В конце концов "любую задачу можно решить на" (с).
VD>> А Java/C# — это сначало ООП, потом обобщенное программирование, а потом все что угодно, но не С.
E>Обобщенное программирование на Java Это забавно. E>Ну тогда расскажи мне, как на Java (либо C#) реализовать такое: E>
Ты меня уж извини, но я эту хрень понять то немогу без серьезного объяснения. Кстати, не пойми мои слова так как будто мне нужно это обяснение. Я и так знаю, что на C# можно написать все что можно написать на С++. Так что смысла развивать эту тему нет.
Если тебе просто хочется поглядеть как та или иная задача решается на шарпе, то порудись сформулировать ее в двух-трех строчках не приводя кучи некому не нужных подробностей. Тогда я без труда предлажу решение на шарпе. Изучать же тонны награмождений у меня желания нет.
Что касается обобщенного программирования, но оно несомненно поддерживаетя в Яве и Шарпе. Только к макросам отношения не имет, как шаблоны С++. По этому оно позволяет писать обобщенный код, но основанный на ООП, а не на текстуальных совпадениях.
E>Или может я под обобщенным программированием понимаю что-то другое.
Возможно. Если это так, то советую привести свою терминологию в соотвествие с общепринятой: http://en.wikipedia.org/wiki/Generic_programming
E>Ага, Грослинг в проекте Green как раз думал про IDEA для Oak.
Просто уверен в этом. И про серверы приложений в которых можно менять компоненты на ходу. И про апплеты подгружаемые по требованию.
VD>> Они принципиально компонентные, модульные, динамические и ООП. А отказ произошел не просто от совместимости с С (C# в ансэфе очень близок к С), а от всего что затрудняет реализацию главных концепций. А в С++ таких вещей оказалось куда больше. С как раз был содран в C#-е очень близко. Отказались только от макросов и инклюдов. Даже препроцессор частично остался.
E>Опять-таки, С# многое взял от C, а C++ вообще побоку остался. Ну да ладно, ты C# знаешь, тебе виднее.
Тут уже не причем ни С, ни С++ при их создании про поддржку компетентной парадигмы никто даже не задумался. Причем если с С все ясно, тогда про нее и не знали. То в С++ — это досадное упущение было вызвано глупым стремлением добиться 100%-ной совместимости с С (кстати, ее так и не добились).
E>>> А отказ от принципа "ты платишь только за то, что используешь" позволил сохранять в программе массу дополнительной метаинформации.
VD>>Это вообще не ясное утверждение. Метоинформация я имел еще в 95-ом году в виде TLB от COM-объектов. И как не странно создавал эти СОМ-объекты я на С++.
E>И имел эту информацию только для того, что было связано с COM. Если же у тебя была в коде какая-нибудь структурка Point, не имеющая к COM-у никакого отношения, то и метаинформации для нее у тебя не было.
Без разницы что я имел. Захотел бы — описал бы все типы в IDL.
E> А в Java для любого класса/интерфейса сохраняется метаинформация. Нужна она тебе будет, не нужна она тебе будет -- она у тебя все равно будет. Хочешь ты того, или нет.
И что? В МС++ она тоже сохраняется, но все С++-код компилируется и выполняется с той же эффектиностью.
Ты сам то не наблюдаешь отсуствия связи между "ты платишь только за то, что используешь" и "сохранять в программе массу дополнительной метаинформации"? Чем я плачу за наличие метаинформации если я ее не использую? Место м на диске что ли? Ну, так дотнетные программы компактнее чем аналогичные анменеджед, хотя и содержут метаинформацию.
E>>> Что сделало возможным такие вещи, как рефлекшен.
VD>>Чууушь!
E>Попробуй доказать, что рефлекшен возможен без метаинформации.
Чушь что к этому привел 'отказ от принципа "ты платишь только за то, что используешь"'.
Я уже говорил, что аналог рефлексии был доступн в КОМ который моно было реализовывать на С++.
E>>> А использование байт-кода и виртуальной машины в Java позволило применять такие механизмы, как динамическая загрузка кода и интанцирование объектов по имени класса.
VD>>Опять берем КОМ и даже Корбу и понимаем, что все эти утверждения высасоны из пальца.
E>Опять берем КОМ или Корбу, или ручную загрузку DLL с GetProcAddress. И пытаемся создать экземпляр класса RECT по имени "RECT". Или WNDCLASS. Или POINT.
А что есть какие-то проблемы с этим? Мне кажется, что тут даже ком не понадобится.
Но ты же говоришь, что "использование байт-кода...позволило применять динамическую загрузкую кода". Я тебе на это и отвечаю, что это возможно без байткода. Что невозможно? Нахрена тут байт-код или даже виртуальная машина?
E>Так ведь за счет чего произошло это упрощение?
Хороший вопрос!
E> Смотрим в The C++ Programming Language 3rd, приложение B "C++ Code That Is Not C":
Ааатличный источник для поиска ответа на этот хаароший вопрос!
E>...Вот и подумай, намного ли проще стало программировать на "улучшеном С", если бы оттуда выбросили выделенные жирным возможности.
А какая разница? Речь то не об этом. (Хотя конечно даже шаблоны и увеличение типобезопастности уже сильно улучшили бы язык.) Речь о том, что С++ несомненно упростил программировани по сравнению с С тем что ввел в ОО-парадигму и сделал язык более типобезопастным. Но точно так же C# упростил программирование по сравнению с С++, так как вел копонентную и фнкциональную парадигмы, а так же завершил процессс начатый в С++ и сделал язык полностью типобезомастным.
В общем, суть в том, что прорыв С++ был в том, что он упростил программирование по сравнению с С. Прорыв же Шарпа в том, что он упростил программировани даже по сравнению с С++. В общем, равитие оно и есть развитие.
И путь, кстати, похожий. В свое время С++ многие отвергали так как считали, что С++ мнее эффективный язык чем С. Классным примером тому является то что создатели Windows NT в начале работы провели эксперементы с С++ и пришли к заключению, что для создания ОС этот язык не подходит, так как менее эффективен чес С. Прошло 15 лет, и за такие слова уже могут начать вставлять клизьмы в голову. Причем этих людей можно понять. Ведь если не использовать С++ как ООЯ, то он действительно может быть эффективнее С, так как позволяет обобщать код за счет шаллонов, а не за счет интерпретации указателий. К тому же С++ содержим разные inline-ы которые позволяют еще больше увеличить скорость кода. Фигня что современные компиляторы игнорируют это слово считая себя умнее программистов. И фигня, что при компиляции С-кода этот же компилятор способен сам заинлайнить нужные функции. Нлавное, что можно создать пример, в котором С окажется мнее эффективным нежели С++. Вот така фигя.
E>>> Но дальше они не пошли. Ведь что мы имеем в C++: статическая типизация; иерархия классов; объекты, которые не могут изменить свой тип (класс) в процессе жизни; передача сообщений между объектов в виде синхронного вызова методов. То же самое происходит в Java/C# с некоторыми изменениями/дополнениями (вложенные и анонимные классы в Java или делегаты в C#).
VD>>Ну, начать с того, что делегатов то в С++ мы как раз не имеем.
E>Научись читать написанное собеседником.
Ладно. Будем учиться вместе.
VD>> Еще в С++ мы как раз не имеем той самой компонентной модели. За то мы имеем в нем целую кучу граблей, неудосбтв и грязи в синтаксисе. От всего этого и избавляют Java/C#.
E>В Java компонентность возможна только для Java и JVM. На C++ подобная компонентность доступна без проблем, если использовать один и тот же компилятор и не пытаться интегрироваться с чужим кодом через COM-подобные извращения.
Извини, но явно не понимашь того что такое компонентность и ее поддержка языком. Простой пример. Попробуй создать два типа в разных модулях (ну, например длл-ках). Обе ДЛЛ-ки должны быть скомпилированы без знания о наличии второй. То есть никакой код из одной не должен быть доступен при компиляции другой. Один из типов должен быть шаблоном. Так вот. Попробуй теперь написать третий модуль (предположим ЕХЕ) который загрузит два предыдущих, возмет из одного шаблон, из другого второй тип и создаст экземляр шаблона параметром типа которого будет указан тип из второго модуля. Вот кога неуправляемый С++ это сможет сделать без костылей вроде КОМ-а, тогда можно будет делать такие утверждения.
E>>> Но здесь нет смены парадигмы.
VD>>Да, есть. КОП > ООП.
E>Интересно.
Очень! Ты жеже не очень редствляешь насколько!
VD>>А C# еще и функциональный стиль привносит.
E>Так же как и C++ с STL и bind-ами/функторами.
. Попробуй его реализовать на досуге.
E>>> Понятно, что сменились некоторые приемы, где-то используется рефлекшен вместо шаблонов, где-то делегаты вместо указателей на методы.
VD>>Да, не вместо. А вместо отуствия.
E>Опять ты за свое. E>Ну уж на этот раз ветку Функциональные типы (параллельная ветка)
И что ты там меня переубедил?
E>>> Но это не принципиально. Принципиальными изменениями, например, могли бы стать: E>>>- асинхронная доставка сообщений;
VD>>Да, есть она. Любой делегат можно вызвать асинхронно
E>Делегат и простой вызов метода, который на самом деле выполняется где-то асинхронно, это, имхо, разные вещи.
Погоди. Делегат — это часть языка описанная в спецификации. В спецификации же фзыка описаны методы делегата (это ведь типа класс) позволяющие вызывать его иссинхронно. Вот тебе простой примерчик:
using System;
class Program
{
delegate int SumDelegate(int[] array, int start, int count);
static void Main()
{
int[] array = new int[]{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Console.WriteLine("Сумируем синхронно. Результат: "
+ Sum(array, 0, 10));
SumDelegate sum1 = Sum;
SumDelegate sum2 = Sum;
IAsyncResult ar1 = sum1.BeginInvoke(array, 0, 5, null, null);
IAsyncResult ar2 = sum2.BeginInvoke(array, 5, 5, null, null);
ar1.AsyncWaitHandle.WaitOne();
ar2.AsyncWaitHandle.WaitOne();
Console.WriteLine("Сумируем Асинхронно. Результат: "
+ (sum1.EndInvoke(ar1) + sum2.EndInvoke(ar2)));
}
static int Sum(int[] array, int start, int count)
{
int end = start + count - 1;
int sum = 0;
for (int i = start; i <= end; i++)
sum += array[i];
return sum;
}
}
Если результат ждать ненужно, то все вообще просто как три копейки. Вызываем BeginInvoke и забиваем на все остальное.
E> Некоторые методы объекта могут расматриваться не как функции, возвращающие какой-то результат (для которого синхронность в том или ином виде необходима), а как сигналы. Например, start или shutdown. Представь себе, что в языке есть возможность: E>
E>class My_Process
E> {
E> public :
E> async start();
E> async shutdown();
E> };
E>My_Process * process = new My_Process();
E>process->start(); // А где и когда он будет работать, уже не важно.
E>
Результат тоже не важен?
Тогда все просто:
My_Process process = new My_Process();
((SomeDelegate)process.start).BeginInvoke(); // А где и когда он будет работать, уже не важно.
E>>>- изменение иерархии классов по ходу работы программы;
VD>>Классов? А какие тогда они классы? А порождать новые классы и их экземпляры можно. Только это уже фрэймворк, а не язык.
E>Ну вот видишь, мы тут с Dyoma говорили о том, что следующий язык программирования потребует смены мышления. Я привожу один пример такого изменения -- считать, что классы -- это такие же переменные сущности, как и объекты. Поэтому они могут быть модифицированны во время работы программы. А ты в штыки сразу же.
E>Вот в Ruby,
Руби динамический язык в котором на производительность вообще никогда не смотрели. Да и с безопстностью программирования в нем не здорово.
Для статически типизированного языка такие фокусы не катят. Да и идеологически вредно.
E> например, все классы являются открытыми. Это означает, что если мы в одном месте напишем: E>
E>class SomeClass
E> ...
E>end # Думаешь, что определение класса SomeClass завершено?
E>
E>то это не означает, что класс SomeClass окончательно пределен. Отнюдь. Где-нибудь дальше мы можем дополнить это описание: E>
E>class SomeClass
E> ...
E>end
E>
E>и новое содержимое SomeClass будет добавлено к сделанному ранее определению класса SomeClass. Более того, мы можем сделать так: E>Файл test.rb E>[code] E>class Test E> def hello E> puts "Test#hello" E> end E>end
Здорово. И что будет если объявят две разных реализации? А ну, как одна другую переопределит? Все идеи полипорфизма идут лесом, так как тперь все можно менять на ходу.
Ох и не умешь ты двавать локоничных простых примеров. Ведь про подмешивание в руби ты же сам недавно привел пример. И там все было просто. Зачем ты сейчас вылил столько ненужной информации. В общем, я все это поскипал даже не досмотрев до конца. И еще раз повторюсь, научить в рпимерах выражать суть, а не важные вещи опускать. Не дай бог тебе когоу учить еидется...
E>Затем через eval расширяем класс Test
Вот это и нужно было сказать. Веся твоя гора кода только путает.
E> и добавляем метод bye. Вызваем его у уже существующего объекта t. Получаем ожидаемый результат -- вызов нового метода. E>Затем через require подгружаем файл, в котором класс Test опять модифицируется. Причем мало того, что мы переопределяем метод hello, так еще и подмешиваем модуль Sample. В результате у давно существовавшего объекта t не только вызывается модифицированный метод hello, но и подмешанный метод something.
Здорово. И того. Эффективность такого кода == нулю. Предстазуемость даже меньше нуля. Отпадный дизайн!
E>А если вспомнить, что подмешанные модули в Ruby становятся непосредственными суперклассами, то получаем модификацию иерархии наследования на этапе выполнения.
Ага. Причем кем угодно. Например, вирусом. Лафа!
ОО-программах типизация должна быть типзацией, а не утиными историями.
E>Стереотип. Замшелый.
Но я просто не хочу использовать язык нарушающий этот стереотип. Если мне нужно будет подобное решение, я добавлю свойство с хэш-таблицей и получу тоже самое но безопастно и быстро.
VD>>Дык и Смолтокщики тоже утверждают. Так вот ходят оба вместе с Лиспщиком и утверждают... рядом с толпами С++-ников, C#-щиков и других Дельфистов.
E>Имхо, тому виной необычный синтаксис и форма записи выражений в Lisp и Smalltalk.
Согласен. Вот мы сидим и ждем когда в языках с понятным синтаксисом появятся те же возможности.
E>А если приблизить этот синтаксис к более распространенным нотациям (С-шной или Паскалевидной), то ситуация может измениться. Вот в Ruby такое приближение уже сделали.
Думаю, ты понимашь, что у Руби круг пользователей не шире чем у Смолтока. Да и перекосило этот Руби конкретно. На С и Паскаль ну совсем не похоже. Нарушает ведь сабака их главные принципы — декларация и типизация всего что испоьзуется.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, eao197, Вы писали:
E>Вот ты мне скажи, появился C# 1.0, ты что, сразу на нем production системы писать стал? Или же поприглядывался, потестировал, пару-тройку пробных проектов сделал, а потом уже с C++ соскочил?
Ну, мне проще. Я художник не местный... попишу и уеду (с)
В общем, через месяц проб я уже на плюсы начал смотреть с отвращением. Через пол года уже казалось, что С++ был сном.
E>Здесь не столько твое отношение к Ruby имелось в виду. Вообще, если я сейчас начну своим коллегам предлагать перейти на Ruby, то ничего из этого не выйдет. Просто потому, что про языки, вроде Ruby или Python-а очень мало кто знает. Т.е. названия-то многие слышали. Кто-то даже знает, что в Python структуризация отступами делается. А вот реальные возможности этих языков, я думаю, представляют себе не многие. И переубедить из можно только предьявив работающий код и многократно повторив, какой же Ruby замечательный язык.
Агащазблин. Вот лично ты пишешь ответ на Янусе. Значит работающий код видишь. Слышишь (постоянно"!) о премуществах дотнета (ну, хотя бы от меня). И что? У тебя даже мысли попробовать по серьезнее не возникло. А ты хочешь чтобы твои коллеги на японский Рулби клюнули? Блажен кто верует.
E>Ну а динамическая природа Ruby и его интерпритируемость... Не привычно, по началу. Ну что же, у каждого свои недостатки. Да и недостатки ли? То, что для кого-то проблема, для другого -- возможность. Так что будем из динамической типизации выжимать все лучшее.
Успехов.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
E>>Здесь не столько твое отношение к Ruby имелось в виду. Вообще, если я сейчас начну своим коллегам предлагать перейти на Ruby, то ничего из этого не выйдет. Просто потому, что про языки, вроде Ruby или Python-а очень мало кто знает. Т.е. названия-то многие слышали. Кто-то даже знает, что в Python структуризация отступами делается. А вот реальные возможности этих языков, я думаю, представляют себе не многие. И переубедить из можно только предьявив работающий код и многократно повторив, какой же Ruby замечательный язык.
VD>Агащазблин. Вот лично ты пишешь ответ на Янусе. Значит работающий код видишь. Слышишь (постоянно"!) о премуществах дотнета (ну, хотя бы от меня). И что? У тебя даже мысли попробовать по серьезнее не возникло.
Но ведь ты не прекращаешь попытки доказывать преимущества дотнета.
Почему же я должен.
Кстати, без обид, но Янус не выглядит той программой, на которую посмотришь и скажешь -- фигня этот C++, нужно на C# программировать.
Точно так же меня отворотило от декстопных программ, написанных на Java и Swing-е. Вроде бы все нормально, но большое и неповоротливое.
VD> А ты хочешь чтобы твои коллеги на японский Рулби клюнули? Блажен кто верует.
Да уж я такой, упертый. Оказываюсь от своих идей только когда дохожу до полного упора.
Кроме того, есть, имхо, работающий рецепт: нужно дать людям удобный и уникальный инструмент. Если он будет востребован, то дальше и вся технология окажется восстребованной.
Вот, например, Mxx_ru. Удобство описания проектов на нем на уровне SCons, если не выше. Многие нюансы C++ (например, static/shared RTL, single/multi threading, RTTI on/off) в нем автоматом учитываются и отслеживаются несоответствие требований и подпроектов. Про Makefile наши C++ разработчики даже и не слышали. В результате -- Ruby есть на каждой машине C++ разработчика. А это значит, что на Ruby я могу делать кодогенераторы для C++ и их использование в C++ проекте не будет требовать для программиста дополнительных усилий. И так далее.
-- собственное объектное хранилище и сериализация для C++. Велосипед, наколенная поделка. Так оно и есть, и отношение до поры, до времени, соответствующее было. Пока не пришлось делать сохранение в БД сложных C++ объектов (со списками полиморфных объектов, которые в свою очередь могли содержать свои списки и т.д.). Попробовали пару объектов вручную по SQL таблицам раскидать. Устали. Искать ORM для C++? Можно было, только время и деньги не лишние, однако. В ObjESSty же эта задача занимала всего несколько строк. Такие вещи меняют отношение к технологиям.
Так что я надеюсь, что у меня не абстрактная вера в свою правоту. Я стараюсь ее подкреплять собственными разработками.
E>>Ну а динамическая природа Ruby и его интерпритируемость... Не привычно, по началу. Ну что же, у каждого свои недостатки. Да и недостатки ли? То, что для кого-то проблема, для другого -- возможность. Так что будем из динамической типизации выжимать все лучшее.
VD>Успехов.
Спасибо.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, VladD2, Вы писали:
E>>Интересное мнение. Итак, мы имеем: процедурный (не ОО) язык С, произошедший от него ОО язык С++, ОО языки Java/C# (появившиеся гораздо позже C++). При этом утверждается, что Java и C# напрямую производные от C, а не от C++. Вероятно, ты считаешь это логичным. Я -- нет.
VD>Ну, у меня в отличии от тебя для этого есть обоснование. Если бы C# произошел от С++, то он должен был бы быть или совместим с С++ снизу в верх, или хотя бы быть сильно на него похожим, для чего опять же пришлось бы взять все что было и возможно отбросить некоторые плохие (по мнению создателей Шарпа) идеи.
Если следовать твоей логике, то скажи, с каким языком Шарп совместим сверху вниз. Или хотя бы снизу вверх.
E>>Имхо, в первой версии Java не было шаблонов потому, что шаблоны только-только появились в C++ и еще не были такой важной частью языка, какой они являются сейчас.
VD>Только что? Ява вышла в 95-ом (или даже в 96-ом) году. Шаблоны в С++ использовались начиная с начала девяностых. Так что уже 5 лет как шаблоны были. А уж C# вышел в 2002-ом. Что же ему помешало лучше скопировать предка? Не уж, то времени нехватило?
.
VD>Для статически типизированного языка проблема решается только введением статического полиморфизма. VD>Итак появилась дилемма. Статический полиморфизм испортит компонентность языка. Но без него получается излишний динамизм да еще и пусор в коде. VD>Дилема и была решена введением дженериков. Дженирики это полу-статический, полу-динамический полиморфизм. Декларируется он статически, но проверяется и поддерживается на стадии джит/преджит-копмиляции. У С++ такой возможности, честно говоря, небыло. У него просто отсуствовала такая стадия. Но у него отсутствовала и потребность быть копонентным. Такая потребность появилась только в девяностых, но к тому времени С++ уже сформировался.
Термин "статический полиморфизм", который тебе так нравится, для меня не сильно понятен. Имхо, что-то подобное в C++ есть в compile-time на основе классов-стратегий.
VD>Мы ведем речь о C#. Он появился в 2002 году. Так что твоя гипотиза о незхватке времени явно некатит. Успели же они пол языка переработать? Ввели свойства, foreach, индексаторы, перечисления, делегаты, события, полиморфизм массивов, препроцессор (да, фиг все упомнишь!), а такую важную часть С++ добавить забыли? Дудки!
Тогда объясни мне, почему, если первая версия C# появилась в 2002 году, шаблоны C++ уже зарекомендавали себя по полной, даже в Java заговорили о появлении в 1.5 generic-ов, а в C# 1.0 их не было?
E>>До того, как в C++ появились нормальные шаблоны, в С++ прежде всего было ООП, а затем уже C.
VD>До того как в С++ появились шаблоны в С++ появился С! И этим все сказано.
А мне казалось, что сначала появился C, затем в него добавили ООП и получился C++
VD>И это не еденичный случай! Это уже традиция. На сегодня в С++ именно что сначала С, потом шаблоны, а помто уже ООП. Причем можно даже без ООП вообще. С то с шаблонами есть же?
Это у тебя, вероятно так. А у меня получается что-то среднее, между ACE (который ругают за стиль "C с классами") и Boost-овскими шаблонными наворотами. Я уже даже не помню, когда вызывал какой-нибудь strlen, strcat, strcmp, fopen, sprintf. Так что C уже где-то далеко в прошлом.
E>>Пора бы уже осознать, что C++ -- это другой язык, нежели C.
VD>С++ язык в котором без проблем можно программировать по разному. Можно в С поиграть. Можно в ООП побаловаться. А можно даже под Лисп покасить. Причем именно С в нем удается лучше всего. Отличный, надо сказать, С плучился! А вот ООП уже получается натянутый.
Да ладно тебе. В C# по-твоему, не натянутый? Если, следуя ООП объекты взаимодействуют между собой путем отсылки сообщений, то где это в C#? В Ruby, например, это так. Там можно вызовы методов (сообщения) перехватывать, сохранять, передавать другому или воспроизводить через какое-то время. В C# это возможно?
VD> И все из-за экономии. А экономить ведь так хочется! Ну, нет по умолчанию виртуальных деструкторов. Ну, и что (казалось бы)? А на деле выходит, что программист думает — "Ага! Если я его добавлю, то объект распухнет на 4 или даже больше байт! А это тормоза и неэффективное испоьзование ресурсов коструктора!" — лучше бы он этих слов и не знал — "Ткк зачем мне это? Ну, его на фиг этот вирутальный деструктор. Вот появятся виртуальные функци тогда добавлю. А пока извернусь...". Но виртуальных функций тоже не появляется (ну, ты понял по каким причинам). И начинаем мы вместо ООП на С++ делать эмуляцию ООП на С с классами. Далее все это удобряется изрядной порцией шаблонов больше похожих на шифровку и...
И что и?
Представь себе, что мне нужен контейнер из миллиона неполиморфных объектов. По четыре лишних байта на каждый: +4Mb. Память нынче не ресурс, однако
Ладно. А как производительность? Если размер объекта без виртуальных функций -- 28 байт, а с виртуальным деструктором -- 32 байт, то объекты с виртуальными деструкторами будут занимать на 14% больше места. При линейном проходе по такому вектору с миллионом объектов насколько чаще придется данные в кэш процессора подгружать? И что это, как не просад производительности на ровном месте?
E>> Он просто вырос из C и долгое время поддерживал совместимость с C.
VD>Хм... Не долгое время, а все время.
Ничего подобного. По крайней мере со стандартом C99 нынешний C++98 точно не совместим.
VD>>> А Java/C# — это сначало ООП, потом обобщенное программирование, а потом все что угодно, но не С.
E>>Обобщенное программирование на Java Это забавно. E>>Ну тогда расскажи мне, как на Java (либо C#) реализовать такое: E>>
VD>Ты меня уж извини, но я эту хрень понять то немогу без серьезного объяснения. Кстати, не пойми мои слова так как будто мне нужно это обяснение. Я и так знаю, что на C# можно написать все что можно написать на С++. Так что смысла развивать эту тему нет.
VD>Если тебе просто хочется поглядеть как та или иная задача решается на шарпе, то порудись сформулировать ее в двух-трех строчках не приводя кучи некому не нужных подробностей. Тогда я без труда предлажу решение на шарпе. Изучать же тонны награмождений у меня желания нет.
Ok. Я всего лишь хотел сказать, что если у объекта типа T мне нужно вызвать методы get_val и get_another_val в C++ шаблоне, то мне не нужно, чтобы T был унаследован от какого-то интерфейса с методами get_val и get_another_val. В C#-генериках чтобы такое провернуть, мне нужно указать ограничение where с именем такого интерфейса. А в моем случае для типов deliver_sm_t и data_sm_t такого интерфейса нет. В C# мне бы его пришлось вводить. А вот C++, Smalltalk или Ruby -- нет.
VD>Что касается обобщенного программирования, но оно несомненно поддерживаетя в Яве и Шарпе. Только к макросам отношения не имет, как шаблоны С++. По этому оно позволяет писать обобщенный код, но основанный на ООП, а не на текстуальных совпадениях.
E>>Или может я под обобщенным программированием понимаю что-то другое.
VD>Возможно. Если это так, то советую привести свою терминологию в соотвествие с общепринятой: VD>http://en.wikipedia.org/wiki/Generic_programming
Смотрим:
In computer science, generics is a technique that allows one value to take different datatypes (so-called polymorphism) as long as certain contracts such as subtypes and signature are kept. The programming style emphasizing use of this technique is called generic programming.
Так вот в C# обобщенное программирование понимается в терминах subtypes. А в C++ или Ruby -- в терминах signatures.
E>>Ага, Грослинг в проекте Green как раз думал про IDEA для Oak.
VD>Просто уверен в этом. И про серверы приложений в которых можно менять компоненты на ходу. И про апплеты подгружаемые по требованию.
Да уж. Если бы камни могли говорить...
VD>Ты сам то не наблюдаешь отсуствия связи между "ты платишь только за то, что используешь" и "сохранять в программе массу дополнительной метаинформации"? Чем я плачу за наличие метаинформации если я ее не использую? Место м на диске что ли? Ну, так дотнетные программы компактнее чем аналогичные анменеджед, хотя и содержут метаинформацию.
Местом в памяти. И скоростью работы программы (т.к. какой-то процент быстродействия тратится на обработку метаданных, которые мне совершенно не нужны).
VD>Я уже говорил, что аналог рефлексии был доступн в КОМ который моно было реализовывать на С++.
Да, но не полной рефлексии, как в Java или Ruby. А только рефликсии для того, за что ты заплатил.
E>>Опять берем КОМ или Корбу, или ручную загрузку DLL с GetProcAddress. И пытаемся создать экземпляр класса RECT по имени "RECT". Или WNDCLASS. Или POINT.
VD>А что есть какие-то проблемы с этим? Мне кажется, что тут даже ком не понадобится.
А что нет? Есть у тебя программа на C++, которая вообще не работает с типом RECT. Как ты ее заставишь создавать эти объекты?
В то же время, в Java или Ruby через Class.forName (Java) или eval (Ruby) я могу по имени создать экземпляр любого класса, который есть в стандартной библиотеке.
E>>Научись читать написанное собеседником.
VD>Ладно. Будем учиться вместе.
VD>>> Еще в С++ мы как раз не имеем той самой компонентной модели. За то мы имеем в нем целую кучу граблей, неудосбтв и грязи в синтаксисе. От всего этого и избавляют Java/C#.
E>>В Java компонентность возможна только для Java и JVM. На C++ подобная компонентность доступна без проблем, если использовать один и тот же компилятор и не пытаться интегрироваться с чужим кодом через COM-подобные извращения.
VD>Извини, но явно не понимашь того что такое компонентность и ее поддержка языком. Простой пример. Попробуй создать два типа в разных модулях (ну, например длл-ках). Обе ДЛЛ-ки должны быть скомпилированы без знания о наличии второй. То есть никакой код из одной не должен быть доступен при компиляции другой. Один из типов должен быть шаблоном. Так вот. Попробуй теперь написать третий модуль (предположим ЕХЕ) который загрузит два предыдущих, возмет из одного шаблон, из другого второй тип и создаст экземляр шаблона параметром типа которого будет указан тип из второго модуля. Вот кога неуправляемый С++ это сможет сделать без костылей вроде КОМ-а, тогда можно будет делать такие утверждения.
А расскажи мне, как третий модуль возьмет два типа из двух других модулей? Просто по имени? Не зная даже, какие интерфейсы они поддерживают?
VD>>>Да, есть. КОП > ООП.
E>>Интересно.
VD>Очень! Ты жеже не очень редствляешь насколько!
Ok. Век живи, век учись.
E>>>> Понятно, что сменились некоторые приемы, где-то используется рефлекшен вместо шаблонов, где-то делегаты вместо указателей на методы.
VD>>>Да, не вместо. А вместо отуствия.
E>>Опять ты за свое. E>>Ну уж на этот раз ветку Функциональные типы (параллельная ветка)
поднимать не будем.
VD>И что ты там меня переубедил?
А ты меня?
VD>>>Да, есть она. Любой делегат можно вызвать асинхронно
E>>Делегат и простой вызов метода, который на самом деле выполняется где-то асинхронно, это, имхо, разные вещи.
VD>Погоди. Делегат — это часть языка описанная в спецификации. В спецификации же фзыка описаны методы делегата (это ведь типа класс) позволяющие вызывать его иссинхронно.
E>> Некоторые методы объекта могут расматриваться не как функции, возвращающие какой-то результат (для которого синхронность в том или ином виде необходима), а как сигналы. Например, start или shutdown. Представь себе, что в языке есть возможность: E>>
E>>class My_Process
E>> {
E>> public :
E>> async start();
E>> async shutdown();
E>> };
E>>My_Process * process = new My_Process();
E>>process->start(); // А где и когда он будет работать, уже не важно.
E>>
VD>Результат тоже не важен? VD>Тогда все просто: VD>My_Process process = new My_Process(); VD>((SomeDelegate)process.start).BeginInvoke(); // А где и когда он будет работать, уже не важно.
И ты думаешь, что запись: ((SomeDelegate)process.start).BeginInvoke -- это нормально? Да еще при условии, что SomeDelegat где-то должен быть описан.
E>>Вот в Ruby,
VD>Руби динамический язык в котором на производительность вообще никогда не смотрели. Да и с безопстностью программирования в нем не здорово.
Нормально там с безопасностью. По неверным указателям ничего записать не получится.
VD>Для статически типизированного языка такие фокусы не катят. Да и идеологически вредно.
Так тож для статически-типизированных
E>> например, все классы являются открытыми. Это означает, что если мы в одном месте напишем: E>>
E>>class SomeClass
E>> ...
E>>end # Думаешь, что определение класса SomeClass завершено?
E>>
E>>то это не означает, что класс SomeClass окончательно пределен. Отнюдь. Где-нибудь дальше мы можем дополнить это описание: E>>
E>>class SomeClass
E>> ...
E>>end
E>>
E>>и новое содержимое SomeClass будет добавлено к сделанному ранее определению класса SomeClass. Более того, мы можем сделать так: E>>Файл test.rb E>>
E>>class Test
E>> def hello
E>> puts "Test#hello"
E>> end
E>>end
E>>
VD>Здорово. И что будет если объявят две разных реализации? А ну, как одна другую переопределит? Все идеи полипорфизма идут лесом, так как тперь все можно менять на ходу.
Имхо, идеи полиморфизма здесь как были, так и остались. А вот моменять реализацию чего-нибудь на ходу, не останавливая работающую систему -- это круто. Вот так в on-line баги фиксить, без остановки сервиса!
VD>Ох и не умешь ты двавать локоничных простых примеров. Ведь про подмешивание в руби ты же сам недавно привел пример. И там все было просто. Зачем ты сейчас вылил столько ненужной информации. В общем, я все это поскипал даже не досмотрев до конца. И еще раз повторюсь, научить в рпимерах выражать суть, а не важные вещи опускать. Не дай бог тебе когоу учить еидется...
А я стараюсь давать работающие примеры. Вот тот, что я привел можно прямо сейчас в ruby и смотреть, что получается. А от примеров, которые даже не первый взгляд синтаксические ошибки содержат, меня лично коробит. Нет к ним доверия. Вот и стараюсь, если есть возможность, приводить полные, работоспособные коды.
E>> и добавляем метод bye. Вызваем его у уже существующего объекта t. Получаем ожидаемый результат -- вызов нового метода. E>>Затем через require подгружаем файл, в котором класс Test опять модифицируется. Причем мало того, что мы переопределяем метод hello, так еще и подмешиваем модуль Sample. В результате у давно существовавшего объекта t не только вызывается модифицированный метод hello, но и подмешанный метод something.
VD>Здорово. И того. Эффективность такого кода == нулю. Предстазуемость даже меньше нуля. Отпадный дизайн!
Эффективность? Смотря на каких задачах. Если матрицы обращать, то да. Но и на шарпе ты для этого в unmanaged полезешь. А если SOAP запросы парсить или SQL-сервер дергать -- то выше крыши.
А вот на счет предсказуемости -- так ведь все предсказуемо. Добавил что-то и получил то, что ожидал.
E>>А если вспомнить, что подмешанные модули в Ruby становятся непосредственными суперклассами, то получаем модификацию иерархии наследования на этапе выполнения.
VD>Ага. Причем кем угодно. Например, вирусом. Лафа!
Что-то практика показывает, что вирусам подвержены как двоичные исполнимые файлы, так и word-овские документы. Так что это не аргумент. Ведь не требуется же, чтобы кассиры в банке были в касках, бронежилетах и вооруженные до зубов, на случай ограбления. Для этого охрана есть.
VD>ОО-программах типизация должна быть типзацией, а не утиными историями.
E>>Стереотип. Замшелый.
VD> Но я просто не хочу использовать язык нарушающий этот стереотип. Если мне нужно будет подобное решение, я добавлю свойство с хэш-таблицей и получу тоже самое но безопастно и быстро.
Ага, на Java уже такие костылики придумали. Только уж если такая возможность востребована, то почему бы не сделать ее свойством языка? Ведь это так похоже на C#-повский подход
E>>А если приблизить этот синтаксис к более распространенным нотациям (С-шной или Паскалевидной), то ситуация может измениться. Вот в Ruby такое приближение уже сделали.
VD>Думаю, ты понимашь, что у Руби круг пользователей не шире чем у Смолтока. Да и перекосило этот Руби конкретно. На С и Паскаль ну совсем не похоже. Нарушает ведь сабака их главные принципы — декларация и типизация всего что испоьзуется.
Нет, я надеюсь, что у Ruby круг пользователей будет раза в три пошире, чем у Smalltalk-а.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, VladD2, Вы писали:
VD>Нет. Руби не является GPL (языком общего назначения). Это скриптовый язык. GPL подразумевает, что хотя бы гипотетически на нем можно написать все от драйверов и ядра ОС, до финансового приложения. Руби же принципиально интерпритируем и не годится для некоторых задач.
Ну интерпретируемость ни сколько не мешает гипотетическим возможностям. Хочешь exe получить — засунь в него интрепретатор и исходник этим, при желании, можно даже микроконтроллеры прошивать
Здравствуйте, VladD2, Вы писали:
E>> Поэтому авторы Java просто не оценили вовремя всего потенциала шаблонов.
VD>Напомню. Смолток, Лисп, Окамл, Руби и множество других языков появившихся как за долго до С++, так и сильно после обладают куда более развитыми средствами полиморфизма и при этом не имеют шаблонов.
VD>Для полиморфизма шаблоны не обязательны. <...поскипано...> VD>Для статически типизированного языка проблема решается только введением статического полиморфизма. VD>Итак появилась дилемма. Статический полиморфизм испортит компонентность языка. Но без него получается излишний динамизм да еще и пусор в коде. VD>Дилема и была решена введением дженериков. Дженирики это полу-статический, полу-динамический полиморфизм.
C++ шаблоны и генерики Java не имееют ничего общего, кроме синтаксиса.
template — это действительно шаблон. Комплитор C++ по шаблону создает новый класс\функцию для каждого различного набора параментров template. Это действительно делает возможным статический полиморфизм. Пример (извращение) использования статического полиморфизма:
template<int N> int factorial() {
return N*factorial<N-1>();
}
int factorial<0>() {
return 1;
}
В этом примере определяется статические полиморфная функция factorial. Она действительно полиморфна, потому как ее поведение зависит от аргумента, но этот полимофизм существует только на стадии компиляции. Динамический аналог выглядит примерно так:
abstract class Int {
abstact int factorial();
Int create(int value) {
return value != 0 ? new NotZeroInt(value) : new Zero();
}
}
class Zero extends Int {
int factorial() { return 1; }
}
class NotZeroInt extends Int {
int value;
int factorial() { return value*Int.create(value - 1); }
}
В Java generics — это расширение системы типов и ничего более. Пример:
class ValueHolder<T> {
T value;
T get() { return value; }
void T set(T newValue) { value = newValue; }
В данном случае объявлен обычный java класс ValueHolder, компилятор все вхождения T заменит на java.lang.Object. Все интересное начнется в местах исползования. Компилятор проведет проверку типов:
ValueHolder<List> holder = new ValueHolder<List>();
holder.setValue(new ArrayList()); // ok
holder.setValue(new HashSet()); // error
List list = holder.get(); // ok
Object obj = holder.get(); // ok
Set set = holder.get(); // error
Map map = (Map)holder.get(); // ok
Никакого полиморфизма добиться генериками нельзя. Работать будет всегда один и тоже класс (байт код), не зависимо от классов того, что туда запихивается, достается.
Польза генериков — это способ ввести в код дополнительные ограничения на типы, и получить неявные касты.
VD>Декларируется он статически, но проверяется и поддерживается на стадии джит/преджит-копмиляции.
К джиту генерики тоже никакого отношения не имеют, хотя бы потому генерики можно обмануть:
<T> T create() {
return (T)new String(); // compiler - warning
}
void f() {
String s = create(); // compiler - ok, runtime - ok
List l = create(); // compiler - ok!, runtime - ClassCastException
}
В местах использования методов, возвращающих T компилятор вставляет cast (инструкция JVM checkcast) к значению T в данном месте. В частности скомпилированным последний пример выглядит так:
invokeXXX create // XXX - потому как в данном случае не важно static, virtual, ...
// на вершине стека лежит объект класса String.
checkcast String // Успешно проверили
astore_0 // собственно присваивание s
invokeXXX create // Опять на вершине стека будет String, метод вызвали тоже самый!
checkcast List // Выполняется перед присваиванием вершины стека локальной переменной типа List
// Тут собственно и случится ClassCastException
astore_1 // Эта инструкция выполнена не будет
В частности замена всех T на Object (или другое ограничение) не дает никакой возможности писать:
T t = new T(); // Компилятор сделает один байт код на все случаи жизни, а их может быть много...
T[] t = new T[...]; // Массив в Java тоже знает класс своих елементов
List<T> l = new ArrayList<T>(); // А вот это пожалуйста, после компиляции вместо List<T> останется просто List
VD>У С++ такой возможности, честно говоря, небыло.
У C++ не было наналога checkcast (в компилированном коде) Он сразу переходит к присваиванию:
template<T>
T* copy(T& value) {
return (T*)(void*)new XXX(); // "обманываем" компилятор
}
MyClass c = copy(new MyClass()); // Все в порядке, но где-то потом случится GPF
Здравствуйте, eao197, Вы писали:
E>Кстати, без обид, но Янус не выглядит той программой, на которую посмотришь и скажешь -- фигня этот C++, нужно на C# программировать.
Янус — это пример приложения которое есть только потому, что пишется на дотнете. Янус на С++ так и небыл создан, хотя трепа на эту тему было призрядно.
Что до его неповоротливости, то скажи спасибо С++ программистам из МС, так как основные тормоза Януса — это джет.
E>Вот, например, Mxx_ru. Удобство описания проектов на нем на уровне SCons, если не выше. Многие нюансы C++ (например, static/shared RTL, single/multi threading, RTTI on/off) в нем автоматом учитываются и отслеживаются несоответствие требований и подпроектов. Про Makefile наши C++ разработчики даже и не слышали. В результате -- Ruby есть на каждой машине C++ разработчика. А это значит, что на Ruby я могу делать кодогенераторы для C++ и их использование в C++ проекте не будет требовать для программиста дополнительных усилий. И так далее.
Ага замечательный пример. Уверен, что никто кроме тебя твой труд не оценит. А вот МСБилд и ему подобные решения будут захватывать рынок на ура.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Cyberax, Вы писали:
C>А вообще, идея с бинарным репозиторием исходных файлов, с которым IDE работает напрямую, была опробована в VisualAge for Java. Успешно провалилась
Так дело не бинарности/текстовости. А в том, что единицей версионирования является файл, а не функция (или еще какая часть AST).
Здравствуйте, VladD2, Вы писали:
E>>Кстати, без обид, но Янус не выглядит той программой, на которую посмотришь и скажешь -- фигня этот C++, нужно на C# программировать.
VD>Что до его неповоротливости, то скажи спасибо С++ программистам из МС, так как основные тормоза Януса — это джет.
Ага, а .Net -- это супер-пупер-мега-рулез! Настолько, что в нем приходится использовать кривые МС-поделки на C++, т.к. родного ничего нет. Java нервно курит в сторонке.
E>>Вот, например, Mxx_ru. Удобство описания проектов на нем на уровне SCons, если не выше. Многие нюансы C++ (например, static/shared RTL, single/multi threading, RTTI on/off) в нем автоматом учитываются и отслеживаются несоответствие требований и подпроектов. Про Makefile наши C++ разработчики даже и не слышали. В результате -- Ruby есть на каждой машине C++ разработчика. А это значит, что на Ruby я могу делать кодогенераторы для C++ и их использование в C++ проекте не будет требовать для программиста дополнительных усилий. И так далее.
VD>Ага замечательный пример. Уверен, что никто кроме тебя твой труд не оценит. А вот МСБилд и ему подобные решения будут захватывать рынок на ура.
К захвату рынка я не стремлюсь. Программирую потому, что мне нравится. И делаю то, что мне нравится. Что получается -- показываю. Мне этого вполне достаточно.
... << RSDN@Home 1.1.4 stable rev. 510>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, Павел Кузнецов, Вы писали:
>> E>Алаверды на Ruby: >> E>
>> E>a.inject { |s, v| s += v }
>> E>
>> Ала еще более верды на C#: >>
>> int sum = 0;
>> foreach(int a in array)
>> sum += a;
>>
>> Имхо, читается лучше всех остальных приведенных вариантов.
ПК>C++: ПК>
ПК>int sum = std::accumulate(array.begin(), array.end(), 0);
ПК>
ПК>Имхо, читается еще лучше, т.к. сразу говорит, что именно делает эта строчка.
Ты почти прав.
Но! Плюсовый вариант, в отличие от первых двух "не масштабируется" — поскольку "получение суммы" здесь использовалось только в качестве примера, смена алгоритма "получения результата" сделает С++-ный вариант "невалидным" (и при более-менее нетривиальном алгоритме, в лучшем случае — эквивалентным по читаемости C#).
Но2! Тем не менее, у плюсового варианта самое большое преимущество — он показывает, что мы хотим получить. Т.е. первые два варианта читаются как "зачем-то перебрать все элементы", а третий — "как-то получить с".
BTW, идеальной "записью намерений" для этого случая мне кажется что-то в этом роде:
int sum = 0;
sum += each(array); //ну или each(array.begin, array.end);
Читается "прибавить к сумме каждый элемент последовательности". Поддается легкой модификации:
а) что сделать с элементами (например, += заменим на *=)
б) с какими элементами (заменяем each на select(последовательность, условие) )
Здравствуйте, Dyoma, Вы писали:
D>Ну интерпретируемость ни сколько не мешает гипотетическим возможностям. Хочешь exe получить — засунь в него интрепретатор и исходник этим, при желании, можно даже микроконтроллеры прошивать
Дело не в ЕХЕ. Дело в пригодности для разработки больших проектов кторые могут требочать еще и высокой производительности. Есть мнение что интепретаторы плохо для этого подходят, и почему-то это мнение разделяю.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.