Re[21]: Следующий язык программирования
От: VladD2 Российская Империя www.nemerle.org
Дата: 08.10.05 02:52
Оценка:
Здравствуйте, eao197, Вы писали:

E>Ага, а .Net -- это супер-пупер-мега-рулез!


Мега-не мега, а С++ и правда курит в сторонке... по крайней мере для решения этой задачи силами этого коллектива точно.

E> Настолько, что в нем приходится использовать кривые МС-поделки на C++, т.к. родного ничего нет.


Дык реализовывать БД очень нехочется. А джет был очень удобен так как есть на любой виндовс. Это на сотнях метров он начал тормозить. А по началу все было очень шустро.
Ты вот почему то не хочешь бросить С++ и писать все на руби, а мы должны отказаться даже от готовых копонетов? Джет на сегодня не приговор. Можно MSSQL использовать.

E> Java нервно курит в сторонке.


Ява тоже неплохо подходит для этой задачи. Хотя явно хуже чем дотнет. Но тут выбор пал просто потму, что в то время (да и сейчас) нам было банально интереснее программировать на дотнете.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: Следующий язык программирования
От: VladD2 Российская Империя www.nemerle.org
Дата: 08.10.05 02:52
Оценка:
Здравствуйте, eao197, Вы писали:

E>Если следовать твоей логике, то скажи, с каким языком Шарп совместим сверху вниз. Или хотя бы снизу вверх.


Дык 100%-но нискаким. Ближе всего С и Ява. С биже если сравнивать небезопасное расширение, Ява ближе идеологически. Далее я бы назвал Дельфи и Смолток. За ними С++.

Реально можно смело утвержадать, что Шарп, да и Ява — это сборные солянки. Они брали интересные идеи и пытались собрать из них законченное решение. Это потребовло адаптацию этих решений друг к другу. А так же отказ от некоторых решений. С реди них были множество решений из С++. Думаю, что на С++ смотрели критичнее всего, так как Шарп избежал большинство проблем С++. Тут ПК недавно приводил ссылку на грабли Явы. Там было штук 8 примеров и только один из них я смог полностью вопроизвести на Шарпе. Связан он с автоматическим приведением char к int. Остальные грабли Явы были полностью устранены. Причем все эти грабли заимствованы Явой из С++.

E>Про C# не скажу,


Но мы то про него в основном речь ведем! Ты же утверждашь, что именно он от С++ произошел.

E> а вот в Java явно силенок не хватило, имхо. Очень здорово на эту тему jazzer высказался: Re[11]: Мои впечатления о лекции Н. Вирта в ННГУ 26.09.2005
Автор: jazzer
Дата: 06.10.05
.


В Яве своя идеология. Она действительно чем-то сродни Обероновской. Авторы Явы очень неохотно вносят в язык специализированные фичи. Именно этим они обясняли отсуствие foreach-а, делегатов и шаблонов. Причем они насколько ревностно охраняли Яву от развития, что это привело к конфликту с МС. Именно это и привело к появлению Шарпа и дотнета. МС нашли в Яве фатальный недостаток — ее писали не они! Ну, и попытались его устранить. Получилось вроде неплохо. Не даром говорят, что Шарп это Ява каковой она должна была бы быть изначально.

E>Термин "статический полиморфизм", который тебе так нравится, для меня не сильно понятен. Имхо, что-то подобное в C++ есть в compile-time на основе классов-стратегий.


Под статическим полиморфизмом я подразумеваю полиморфизм доступный еще на стадии компиляции. Сюда относятся перегрузка методов, параметрический полифорфизм.

E>Тогда объясни мне, почему, если первая версия C# появилась в 2002 году, шаблоны C++ уже зарекомендавали себя по полной, даже в Java заговорили о появлении в 1.5 generic-ов, а в C# 1.0 их не было?


Я что-то не улавливаю смысла в этом воросе. К тому же я первый задал вопрос о том почему 2002 году МС недобавил шаблоны в Шарп.

Кстати, даты нужно помнить. Ява 1.5 появилась в 2005. Примерно в это же время появится и C# 2.0. Шаблонов нет ни там, ни там. Есть дженерики, которые и по идеологии, и по реализации сильно отличаются от плюсов. А почему их добавили ясно. Поняли, что языкам нехватает статического полимпорфизма. Собственно об этом я уже говорил, так что повтояться смысла нет. Единственное, что учти, что Ява в 1996 и Ява в 2003 (когда заговорили о дженериках) — это совершенно разные вещи. В 1996 это был медленный интерпретатор с поканым ЖЦ. В 2003 Ява уже не сильно отставала от С++, а кое где даже перегоняла его. В общем в 96-ом могло быть банально не до того.

E>

E>А мне казалось, что сначала появился C, затем в него добавили ООП и получился C++

С как был так и остался. Появился С++. И первым делом в него втавили С. Популизм однако.

VD>>И это не еденичный случай! Это уже традиция. На сегодня в С++ именно что сначала С, потом шаблоны, а помто уже ООП. Причем можно даже без ООП вообще. С то с шаблонами есть же?


E>Это у тебя, вероятно так. А у меня получается что-то среднее, между ACE (который ругают за стиль "C с классами") и Boost-овскими шаблонными наворотами.


А с каких пор буст стал исповедовать ООП? Это обобщенное- и мета-программирование. Так что между "АСЕ и буст" — это значит "между С и С с шаблонами".

E> Я уже даже не помню, когда вызывал какой-нибудь strlen, strcat, strcmp, fopen, sprintf. Так что C уже где-то далеко в прошлом.


А это тут не причем. Хотя тех кто их использут достаточно. Важен дух программированя. В С++ очень часто из-за боязни тормозов вызываемых проверками типов и динамическим полипорфизмом отказываются от чистого ОО-дизайна и испльзуют разные не-ОО-приемы.

E>Да ладно тебе. В C# по-твоему, не натянутый?


Не. В C# ООП очень чистый. Язык проектировался так, что не в ОО-стиле можно программировать только тогда когде без этого никак. Весь язык подталкивает к ОО-стилю.

E>Если, следуя ООП объекты взаимодействуют между собой путем отсылки сообщений, то где это в C#?


Сэр, вы меня пугаете. Вызов экземплярного метода == отсылке сообщений объекту.

E> В Ruby, например, это так. Там можно вызовы методов (сообщения) перехватывать, сохранять, передавать другому или воспроизводить через какое-то время. В C# это возможно?


Издевашся?
Я уже просто стал бояться твоих познаний в ООП. Шарп это чистый ООЯ. Естественно что с полиморфизмом у него впорядке. Но Шарп язык нацеленный на чистый ООП со статической типизацийе. Он не допускает хаков. Изменение поведения делается путем порождения полиморфных типов, перегрузки, параметризированных типов и делегатов. Короче ОО-средств более чем достаточно чтобы нужны в хаках и динамической типизации не возникало.

VD>> И все из-за экономии. А экономить ведь так хочется! Ну, нет по умолчанию виртуальных деструкторов. Ну, и что (казалось бы)? А на деле выходит, что программист думает — "Ага! Если я его добавлю, то объект распухнет на 4 или даже больше байт! А это тормоза и неэффективное испоьзование ресурсов коструктора!" — лучше бы он этих слов и не знал — "Ткк зачем мне это? Ну, его на фиг этот вирутальный деструктор. Вот появятся виртуальные функци тогда добавлю. А пока извернусь...". Но виртуальных функций тоже не появляется (ну, ты понял по каким причинам). И начинаем мы вместо ООП на С++ делать эмуляцию ООП на С с классами. Далее все это удобряется изрядной порцией шаблонов больше похожих на шифровку и...


E>И что и?


Глючный код плохо поддающихся не только рефакторингу, но и чтению.

E>Представь себе, что мне нужен контейнер из миллиона неполиморфных объектов. По четыре лишних байта на каждый: +4Mb. Память нынче не ресурс, однако


И что? Типа в С++ можно сделать тоже самое без добавления этих байтов?
Статический полиморфизм не рассматриваем, так как его можно достигунь и в шарпе используя структуры.

E>Ладно. А как производительность? Если размер объекта без виртуальных функций -- 28 байт, а с виртуальным деструктором -- 32 байт, то объекты с виртуальными деструкторами будут занимать на 14% больше места. При линейном проходе по такому вектору с миллионом объектов насколько чаще придется данные в кэш процессора подгружать? И что это, как не просад производительности на ровном месте?


От именно так и рассуждают 80% С-шников. Экоромия то какая?! Умножаем высасанную из пальца цифру на гипотетические миллионы и... как говорил Райкин — "из этих данных уже можно узнать где у нас аэродромы".

На дизайн приложения при этом уже начхать. Мы же 4 байта сэкономили!

В итогже же оказывается, что С++-ные рпиложения жрут без зазрения сотни метров памяти, глючат по страшному и к томуже не редко тормозят. Но у программиста четкая уверенность, что он то написал куда более производительное приложение нежели тот ламер на управляемомо языке.

E>>> Он просто вырос из C и долгое время поддерживал совместимость с C.


VD>>Хм... Не долгое время, а все время.


E>Ничего подобного. По крайней мере со стандартом C99 нынешний C++98 точно не совместим.


Он и со старым на 100% не совместим. У С есть вещи по другому воспримимаемые С++-компиляторами. Например, функция без параметров:
void f();

рассматривается как:
void f(...);

в С, и как:
void f(void);

в С++.
Отсюда я могу написать в коде на С:
f(1, "aa");

и С-компилятор это проглотит. А С++-компилятор выдаст ошибку.

Просто те кто пишет код на С пытаются делать его совместимым с С++. К тому же файл с расширеним ".с" будет запускать С++-компилятор. В инклюдах же можно разрулить тонкие вещи препроцессором. Для того С++-копиляторы определяют специальный символ препроцессора.

E>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 -- нет.


Ну, начнем с того, что плохой дизайн и проблемы языка ты пыташся выдать за фичу. То что ты описал есть некудышный дизайн. Нормальный дизай как раз заключается втом, чтобы наделить объекты нужным интерфесом. Это позволит использовать все приемущества ООП. Однако если "уж так слажалось", на то есть паттерны проетирования вроде обертки и делегаты (т.е. функциональный стиль) для абстрагирования от объектов.

В общем, тут нужно координально менять мышление. Хотя аналоги есть и в том же С++. Те же алгоритмы СТЛ-я во многом построены на похожих подходах.

А вот с тем что описал ты лучшие умы С++-комьюнити как раз пытаются боросться. Вот почитай про Concepts которые хотят ввести в МС С++ и С++0х (следующую версию стандарта, кстати, почему 0х? сдается мен, что более точно было бы писать хх ).


VD>>Что касается обобщенного программирования, но оно несомненно поддерживаетя в Яве и Шарпе. Только к макросам отношения не имет, как шаблоны С++. По этому оно позволяет писать обобщенный код, но основанный на ООП, а не на текстуальных совпадениях.


E>


Этот смех от недостатка информации.

E>Смотрим:

E>

E>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.


E>Так вот в C# обобщенное программирование понимается в терминах subtypes. А в C++ или Ruby -- в терминах signatures.


Ты явно не понимашь значения написанного. Главное здесь "different datatypes".

Возьмусь перевести этот абзац. Сначала почти дословно:
В компьютерной науке, обобщенное программирование — это техника позволяющая одному и тому же значению принимать разные типы данных (что называется полиморфизмом) пока соблюдаются некоторые контракты, такие как подтипы и сигнатуры.

Короче обобщенное программирование — это возможность опускать информацию о типах используемых при описани функций и/или типов делая таким образом типы и алгортмы полиморфными, т.е. применимыми не к одному, а к целой группе типов.

Дженерики в Яве и Шарпе это делать и повзоляют. Более того, они даже называются дженериками именно потому, что позволяют это делать. Или ты сомневашся, в вернсти названия выбранного для дженериков? Ну, тогда ты редкосный аригизал.

Разница между дженериками и шаблонами заключается в том, что в дженериках те самые контракты можно задать явно при создании дженериков. А в С++ они определяются неявно в момент вопложения шаблона. При этом копилятор С++ просто пораждает код по шаблону, а потом пытается проверить рпзультат на корректность.

В C# же все значительно сложнее. Сначала при создании дженерика компилятор записывает информацию о констрэйне в метаданные сборки. Потом когда та же и или другая сборка хочет использовать этот дженерик компиятор проверят, что тип подставляемый в качестве аргумента типа дженерику удолветворяет констрэнам. Если все ОК, то генерируется мсил использующий дженерик с этим типом. Далее когда рантайм загружает модули производится еще одна проверка констрэйнов и если она прохдит успешно, то пораждается так называемый закрытый тип. Это место практически аналогично воплощению шаблона в С++. Но так как констрэйны полностью уберигают от проблем с несовпадением интерфейса проверка закрытого типа уже не требуется, или всегда проходит успешно.

VD>>Просто уверен в этом. И про серверы приложений в которых можно менять компоненты на ходу. И про апплеты подгружаемые по требованию.


E>Да уж. Если бы камни могли говорить...


А причем тут камни? Ты сам давал цитаты про Оак. Там цели дизайна языка было записано "динамик лэнгвьидж". Это оно и есть.

E>Местом в памяти.


Да? А ты знашь, что исполнимый модуль подгружается путем мапленья на процесс и данные если не используются просто не подгружаются в поамять, или выталкиваются из нее? К тому же метаинформация имеет очень компактный формат изанимает копейки.

E> И скоростью работы программы (т.к. какой-то процент быстродействия тратится на обработку метаданных, которые мне совершенно не нужны).


Гы-гы. Если ты ее не исползуешь, то и время на нее не тратится. Метаинформация используется рантаймом толко при джит-компиляции и создании EEClass-структур. Далее ЖЦ живет только на основании последних. Обращение к метаинформации в процессе работы не идет если конечно не сделать вызов вручную.

VD>>Я уже говорил, что аналог рефлексии был доступн в КОМ который моно было реализовывать на С++.


E>Да, но не полной рефлексии, как в Java или Ruby. А только рефликсии для того, за что ты заплатил.


А какая разница то? Возможно ведь? Ты еще помнишь свои заявления?

И вообще, откровенно говоря использование всех этих предрассудков в качестве аргументации и постоянное переключение с руби на С++ уже надоело. Ты себя уже убдил. Явно аргументы и информация тебе не нужна. Если что еще раз переключишся с С++ на Руби.

E>>>Опять берем КОМ или Корбу, или ручную загрузку DLL с GetProcAddress. И пытаемся создать экземпляр класса RECT по имени "RECT". Или WNDCLASS. Или POINT.


VD>>А что есть какие-то проблемы с этим? Мне кажется, что тут даже ком не понадобится.


E>А что нет?


Нет. Структуры все как одна сишные.

E> Есть у тебя программа на C++, которая вообще не работает с типом RECT. Как ты ее заставишь создавать эти объекты?


Нда. Тяжелый случай. Прийдется ее заставить работать с этими типами.

В общем, кончай юлить. Ты заявил что для динамической загрузки нжен байткод и рантайм. Это не соотвествует действительности и ты это знашь. Что еще обсуждать?

E>В то же время, в Java или Ruby через Class.forName (Java) или eval (Ruby) я могу по имени создать экземпляр любого класса, который есть в стандартной библиотеке.


Ну, и в КОМ я могу создать по имению любой ком-объект. И что? К тому же в Руби нет байткода. Как же он по-твоему умудряется создавать объекты динамически?

Ты или уже забыл суть своих утверждений, или занимашся нерикрытой демагогий. Разговор нужно завязывать. Я не хочу часами опровергать полную фигню. В то время как ты пыташся сменить тему и поймать мнея на слове.

VD>>Извини, но явно не понимашь того что такое компонентность и ее поддержка языком. Простой пример. Попробуй создать два типа в разных модулях (ну, например длл-ках). Обе ДЛЛ-ки должны быть скомпилированы без знания о наличии второй. То есть никакой код из одной не должен быть доступен при компиляции другой. Один из типов должен быть шаблоном. Так вот. Попробуй теперь написать третий модуль (предположим ЕХЕ) который загрузит два предыдущих, возмет из одного шаблон, из другого второй тип и создаст экземляр шаблона параметром типа которого будет указан тип из второго модуля. Вот кога неуправляемый С++ это сможет сделать без костылей вроде КОМ-а, тогда можно будет делать такие утверждения.


E>А расскажи мне, как третий модуль возьмет два типа из двух других модулей? Просто по имени? Не зная даже, какие интерфейсы они поддерживают?


А это твоя проблема. Ты же тут утверждал, что С++ напрямую поддерживает компонентность. Вот и расскажи как. Если тебя интересует как это делается в других компонентрых средах, то могу поделиться. В дотнете и Яве это делается через компонентный АПИ и рефлексию. В КОМ-е через свой АПИ. В любм случае имеется метаинформация и рантайм. Ни того, ни другого в С++ нет. Так что закроем бредовый разговор о компонетности С++. Ее в этом языке попросту нет и никогда не было. Единственное что можно сделать — это написать на С++ компонентный фрэймворк. КОМ как раз прпмер такого фрэймворка. Но назвать его С++ уже тяжело. Ведь как минимум приутсвует копилятор idl.

VD>>И что ты там меня переубедил?


E>А ты меня?


А я ссылки на такие темы не даю.

E>И ты думаешь, что запись: ((SomeDelegate)process.start).BeginInvoke -- это нормально? Да еще при условии, что SomeDelegat где-то должен быть описан.


Не фантан конечно, но твое предложение в языке присуствует. Ты же говорил, что этого нет и это был бы прорыв. Ты же не сказал, что прорыв был бы если бы в C# упростили синтаксис ассинхронного вызова?

Может все же признать, что был не прав? Ну, смешно же. Тебе через раз указывают на твою правоту, а ты каждый раз вместо того чтобы поправить свои рассуждения пыташся сменить тему обсуждения.

E>Нормально там с безопасностью.


Ненормально. Миксины сделаны грязно. Декларации переменных и т.п. не требуется. Это все приводит к граблям.

E> По неверным указателям ничего записать не получится.


Это только одна проблема. Очень важна, но не единственная. Случайно переопределенная переменная или опечатка в имени и ты пошел искать ошибку по всем модулям где может встретиться переенная. А учитывая непродуманные миксины это может быть бюбой модуль.

Так что то что ты хвалишь зачастую является халтурой которая упрощая одно вносит другие проблемы.

VD>>Для статически типизированного языка такие фокусы не катят. Да и идеологически вредно.


E>Так тож для статически-типизированных


В динамических тоже некрасиво получается. Короче, я уже указывал, на то что красивую реализацию видел только в Скле.

VD>>Здорово. И что будет если объявят две разных реализации? А ну, как одна другую переопределит? Все идеи полипорфизма идут лесом, так как тперь все можно менять на ходу.


E>Имхо, идеи полиморфизма здесь как были, так и остались.


Утиные истории тут повсеместно и святая вера в непогрешимость программиста который обязан уповать на правильное кряканье объектов и окуратность товарищей в воспитании своих уток.

Я так понимаю в большом коллективе ты Руби еще не применял? Боюсь, что через некоторое время твоя любовь к уткам может резко уменьшиться.

E> А вот моменять реализацию чего-нибудь на ходу, не останавливая работающую систему -- это круто. Вот так в on-line баги фиксить, без остановки сервиса!


Гы. Ты из какого века? В VC еще в 6.0 была возможность менять код без перезапуска отлаживаемого процесса. В ВБ тоже это было. Сейчас прикрутили к дотнету. Так что усе пучком с изменением кода. Вот структуру классов менять нельзя. Но ее для отладки и не стоит менять.

E>А я стараюсь давать работающие примеры.


Это хорошо. Но в таком кратком языке как Руби они должны умещаться в пол экрана. А у тебя занимают 4. Оставляй суть. Это резко повысить воспроизводимость и понятность твоих примеров.

E> Вот тот, что я привел можно прямо сейчас в ruby и смотреть, что получается.


Здорово. Но прочесть это уже не просто. А понять суть еще сложнее. Можно же сократить ример до демонстрации одной фичи в очень простых условиях?

E> А от примеров, которые даже не первый взгляд синтаксические ошибки содержат, меня лично коробит. Нет к ним доверия. Вот и стараюсь, если есть возможность, приводить полные, работоспособные коды.


Ну, мои примеры тоже в большинстве случаев работают, но 4 экрана это уже класс который можно использовать в реальном приложении. А для демонстрации возможности достаточно 3-20 строк.

E>Эффективность? Смотря на каких задачах. Если матрицы обращать, то да. Но и на шарпе ты для этого в unmanaged полезешь.


Да, вообще-то не зачем. Вот товарищь написал на шарпе 7 сек против против 5. Тут на каком-то сайте оптимизированная версия за (гы-гы) 4.5 выполнялась.

E> А если SOAP запросы парсить или SQL-сервер дергать -- то выше крыши.


Ты редлагашь общий случай. Так что уповать тут на SQL-сервер странно.

E>А вот на счет предсказуемости -- так ведь все предсказуемо. Добавил что-то и получил то, что ожидал.


А ну как если добавил не я и при этом попортил мой код? Когда я один, то утконосизм еще прокатывает. А если это код какого-нить Януса? Бац и на завтра пол приложения в глюках.

E>Что-то практика показывает, что вирусам подвержены как двоичные исполнимые файлы, так и word-овские документы. Так что это не аргумент.


Ты уж меня извини, но в вордоских документах меня спрашивают перед зпуском макроса. А тут можно менять чужой код и нитко не заметит.

E> Ведь не требуется же, чтобы кассиры в банке были в касках, бронежилетах и вооруженные до зубов, на случай ограбления. Для этого охрана есть.


Как это? Ани за стеклом и рядом охранник.

E>Ага, на Java уже такие костылики придумали. Только уж если такая возможность востребована, то почему бы не сделать ее свойством языка? Ведь это так похоже на C#-повский подход


Это рефлексия и т.п. Там проверка безопастности работает. Это тебе не файлик с исходником в дирректорию бросить.

E>Нет, я надеюсь, что у Ruby круг пользователей будет раза в три пошире, чем у Smalltalk-а.


Похоже ты уже прав. Глянул тут на количество проектов на sourceforge.net:
Smalltalk (56 projects)
Ruby (377 projects)
Круче Smalltalk только D и Оберон :
Oberon (0 projects)
D (24 projects)
Оберон даже был обойден Модулой:
Modula (7 projects)

Вот только одно "но". Встретить проект создающийся исключительно на руби трудно. Обычно Руби сочетается с Явой или С++. Так что язык явно не GPL.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: Следующий язык программирования
От: VladD2 Российская Империя www.nemerle.org
Дата: 08.10.05 07:34
Оценка:
Здравствуйте, Dyoma, Вы писали:

D>C++ шаблоны и генерики Java не имееют ничего общего, кроме синтаксиса.


Общее у них то что и то, и другое является средством обобщенного программирования основанного на принципе параметрического полиморфизма. В остальном согласен. Реализации отличаются сильно. Но я о схожести и не говорил. Читай внимательнее.

D>Пример (извращение) использования статического полиморфизма:

D>
D>template<int N> int factorial() {
D>    return N*factorial<N-1>();
D>}

D>int factorial<0>() {
D>    return 1;
D>}
D>


Это не пример "использования статического полиморфизма". Это действительно извращение . Это метапрограммирование на шаблонах использующее побочные эффекты создаваемые компиляторами. К полупорфизму неимеет никакого отношения. Кстати, к нему не имеют отношения даже константные параметры. Это не полиморфизм. Это просто макроподстановка.

D>В этом примере определяется статические полиморфная функция factorial. Она действительно полиморфна, потому как ее поведение зависит от аргумента, но этот полимофизм существует только на стадии компиляции.


Классное определение полиморфизма! Эдак любая функция Паскаля полиморфна если у нее есть аргументы.

Эта функция не полиморфна. Это функция самая обыкновенная за тем исключением, что ее код генерируется во время копиляции за счет побочного эффекта создаваемого при рекурсивном определении шаблона.

Полиморфизм подразумевает использование одного алгоритма к разным типм. Тут тип один, а вот алгоритмы зависят от константы задающий глубину рекурсии.

D>Динамический аналог выглядит примерно так:

D>
D>abstract class Int {
D>    abstact int factorial();
    
D>    Int create(int value) {
D>        return value != 0 ? new NotZeroInt(value) : new Zero();
D>    }
D>}

D>class Zero extends Int {
D>    int factorial() { return 1; }
D>}

D>class NotZeroInt extends Int {
D>    int value;
D>    int factorial() { return value*Int.create(value - 1); }
D>}

D>


Ужас какой! Зачем такие сложности?

D>В Java generics — это расширение системы типов и ничего более.


Только и всего? Гы-гы. Иди прочти поеделение полиморфизма.

D>В данном случае объявлен обычный java класс ValueHolder, компилятор все вхождения T заменит на java.lang.Object. Все интересное начнется в местах исползования. Компилятор проведет проверку типов:

D>
D>    ValueHolder<List> holder = new ValueHolder<List>();
D>    holder.setValue(new ArrayList()); // ok 
D>    holder.setValue(new HashSet());   // error
D>    List list = holder.get();           // ok
D>    Object obj = holder.get();        // ok
D>    Set set = holder.get();           // error
D>    Map map = (Map)holder.get();      // ok
D>

D>Никакого полиморфизма добиться генериками нельзя.

Да они только ради него радимого и существуют. Короче, учи матчасть. А потом внимательнее читай то что я написал.

ЗЫ

А на месте ПК я бы постыдился бы ставить плюсы таким заблуждениям.
Почему только ПК? Ну, eao197 только что сам "плавл" в этом вопросе. Я вообще даже представить не мог, что на нашем сайте в таких вопросах народ "плавает".
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[18]: Следующий язык программирования
От: VladD2 Российская Империя www.nemerle.org
Дата: 08.10.05 07:34
Оценка:
Здравствуйте, Dyoma, Вы писали:

D>(Rectangle createX:1 y:2 width: 3 height: 4) square.


Я согласен, с тем, что именованные параметры иногда очень хорошо отражают суть происходящего. Только вот все равно мне не наравится синтаксис Смолтока. Уж больно быстро он превращается в кашу. Одна/две функции еще приемлемо. Но чуть больше и... Кстати, неплохо именованные параметры сделаны в Васике.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: Следующий язык программирования
От: Andrei N.Sobchuck Украина www.smalltalk.ru
Дата: 08.10.05 08:02
Оценка: 1 (1)
Здравствуйте, Sinclair, Вы писали:

S>На сишарпе все читается очень близко к нормальному английскому:

S>

for each a in array increment sum by a.

S>
S>foreach(int a in array) sum += a;
S>


Таки изобретаем fold?

S>Я бы назвал метод как-нибудь типа perform: initWith:.


Не пойдёт. Если блок будет хоть сколь нибудь большим, то начальное значение затеряется где-то в конце.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Я ненавижу Hibernate
Автор: Andrei N.Sobchuck
Дата: 08.01.08
!
Re[18]: Следующий язык программирования
От: Andrei N.Sobchuck Украина www.smalltalk.ru
Дата: 08.10.05 08:02
Оценка: +1 :))
VD>Похоже ты уже прав. Глянул тут на количество проектов на sourceforge.net:
VD>Smalltalk (56 projects)
VD>Ruby (377 projects)
VD>Круче Smalltalk только D и Оберон :

SF тут слабо подходит по причине ориентации на file-based языки. Нужно смотреть например на SqueakSource(Salty Pickle, Impara) или Cincom Store Repository.

VD>Oberon (0 projects)

VD>D (24 projects)
VD>Оберон даже был обойден Модулой:
VD>Modula (7 projects)

Влад, уважаю! Столько текста набрать. Мне не хватило сил даже полностью всё это прочитать, а уж столько написать — пальцы бы поотпадали
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Я ненавижу Hibernate
Автор: Andrei N.Sobchuck
Дата: 08.01.08
!
Re[18]: Следующий язык программирования
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 08.10.05 09:02
Оценка: 2 (1)
Здравствуйте, VladD2, Вы писали:

E>>Про C# не скажу,


VD>Но мы то про него в основном речь ведем! Ты же утверждашь, что именно он от С++ произошел.


Я сказал, что:

Так вот, имхо, Java/C# стали всего лишь дальнейшей эволюцией C++ времен 1990-1992 годов, а то и еще более раннего периода.

Ну и что тут не так? C++ добавил в C ООП. Затем, имхо, Java/C# пошли по этому пути дальше -- выбросили из C++ часть граблей и добавили фич из других языков. По твоим словам -- КОП. Но принипиальная разница между моим и твоим взглядом на вещи в том, что по-моему, Java/C# стали модифицировать C++ (точнее это сделала Java, а C# уже модифицировал Java), а по-твоему -- что Java/C# по новой добавили в C ООП+КОП (т.е. C++ остался по боку).

Ну да бог с ним. Меня ты не переубедил, а правду пускай историки ищут.

E>>Тогда объясни мне, почему, если первая версия C# появилась в 2002 году, шаблоны C++ уже зарекомендавали себя по полной, даже в Java заговорили о появлении в 1.5 generic-ов, а в C# 1.0 их не было?


VD>Я что-то не улавливаю смысла в этом воросе. К тому же я первый задал вопрос о том почему 2002 году МС недобавил шаблоны в Шарп.


Нашел кому этот вопрос задавать . По мне, так Java/C# -- must die! C++ forever!



VD>Кстати, даты нужно помнить. Ява 1.5 появилась в 2005.


Это ты зря. Сентябрь 2004 года. Официального пресс-релиза на sun.com я не нашел, но вот, например: http://weblogs.java.net/blog/kgh/archive/2004/09/j2se_50_tiger_i.html

E>>Это у тебя, вероятно так. А у меня получается что-то среднее, между ACE (который ругают за стиль "C с классами") и Boost-овскими шаблонными наворотами.


VD>А с каких пор буст стал исповедовать ООП? Это обобщенное- и мета-программирование. Так что между "АСЕ и буст" — это значит "между С и С с шаблонами".


Нет, это значит: "Много 'C с классами' и много с шаблонами". Много, но не черезмерно (камень в огород boost-а)

E>>Если, следуя ООП объекты взаимодействуют между собой путем отсылки сообщений, то где это в C#?


VD>Сэр, вы меня пугаете. Вызов экземплярного метода == отсылке сообщений объекту.


Не-а. Это распространенная догма. Главное противоречие в нем, что "отсылка" это асинхронное понятие, а "вызов" -- это синхронное. Когда мы приравниваем отсылку вызову, то для реализации асинхронного взаимодействия приходится придумывать грабли вроде BeginInvoke/EndInvoke или active в очередном прожекте Саттера.

E>> В Ruby, например, это так. Там можно вызовы методов (сообщения) перехватывать, сохранять, передавать другому или воспроизводить через какое-то время. В C# это возможно?


VD>Издевашся?


Нет. Рассказываю о том, чего узнал.

VD>Я уже просто стал бояться твоих познаний в ООП.


Вот чего я понял про ООП, так это то, что ООП -- это довольно аморфная идея на трех тезисах: инкапсуляция, наследование, полиморфизм. А дальше все разворачивают ООП куда хотят и как хотят. "Закон что дышло...".

VD> Шарп это чистый ООЯ. Естественно что с полиморфизмом у него впорядке. Но Шарп язык нацеленный на чистый ООП со статической типизацийе. Он не допускает хаков. Изменение поведения делается путем порождения полиморфных типов, перегрузки, параметризированных типов и делегатов. Короче ОО-средств более чем достаточно чтобы нужны в хаках и динамической типизации не возникало.


Имхо, перехват методов и последующее их воспроизведение, или трансляция вызова в параллельный поток -- все это возможно и в статически типизированном языке.

E>>Ладно. А как производительность? Если размер объекта без виртуальных функций -- 28 байт, а с виртуальным деструктором -- 32 байт, то объекты с виртуальными деструкторами будут занимать на 14% больше места. При линейном проходе по такому вектору с миллионом объектов насколько чаще придется данные в кэш процессора подгружать? И что это, как не просад производительности на ровном месте?


VD>От именно так и рассуждают 80% С-шников. Экоромия то какая?! Умножаем высасанную из пальца цифру на гипотетические миллионы и... как говорил Райкин — "из этих данных уже можно узнать где у нас аэродромы".


VD>На дизайн приложения при этом уже начхать. Мы же 4 байта сэкономили!


Мой поинт был в том, что если последовать твоему предложению и сделать деструкторы по умолчанию виртуальными, то придется сильно постараться, чтобы от этих 4-х байтов потом избавится.

VD>В итогже же оказывается, что С++-ные рпиложения жрут без зазрения сотни метров памяти, глючат по страшному и к томуже не редко тормозят. Но у программиста четкая уверенность, что он то написал куда более производительное приложение нежели тот ламер на управляемомо языке.


Когда на C# будет написанно столько же, сколько на C++ и таким же количеством ламеров, тогда и можно будет сравнить, кто и сколько жрет памяти и насколько что тормозит.

Пока я, например, слышу от коллег, что IDEA на буке с 512Mb отъедает очередные 150Mb пямяти и тормозит.


E>>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>Ну, начнем с того, что плохой дизайн и проблемы языка ты пыташся выдать за фичу. То что ты описал есть некудышный дизайн. Нормальный дизай как раз заключается втом, чтобы наделить объекты нужным интерфесом. Это позволит использовать все приемущества ООП. Однако если "уж так слажалось", на то есть паттерны проетирования вроде обертки и делегаты (т.е. функциональный стиль) для абстрагирования от объектов.


VD>В общем, тут нужно координально менять мышление. Хотя аналоги есть и в том же С++. Те же алгоритмы СТЛ-я во многом построены на похожих подходах.


Я ожидал, что после моего примера такие упреки появятся -- мол дизайн должен быть правильный. А не правильный, так рефактори. Предсказуемо, скучно.

А ситуация такая: deliver_sm_t и data_sm_t -- это инкапсуляция разных PDU. Между ними есть небольшие пересечения по функциональности. Оба они is-a PDU. Но deliver_sm_t не есть data_sm_t и наоборот.

В одном из приложений мне потребовалось унифицированная обработка как deliver_sm_t, так и data_sm_t. И шаблоны C++ это позволили мне сделать без изменения первоначальной иерархии классов PDU. Если же следовать "хорошему" дизайну, то как только такая унифицированная обработка потребовалась, то нужно делать рефакторинг и вводить интерфейс deliver_and_data_sm_base_t, а затем реализовать этот интерфейс в deliver_sm_t и data_sm_t. Если в другой задаче мне потребуется унифицированная обработка deliver_sm_t, data_sm_t и submit_multi_sm_t (в которых пересечения так же есть), то мне нужно будет сделать очередной рефакторинг и ввести интерфейс deliver_and_data_and_submit_multi_sm_base_t. Увлекательный путь, однако

Вот только C++ шаблоны позволяют решать подобные задачи легко и без лишних усилий (со статической типизацией при этом).

E>>Смотрим:

E>>

E>>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.


E>>Так вот в C# обобщенное программирование понимается в терминах subtypes. А в C++ или Ruby -- в терминах signatures.


VD>Ты явно не понимашь значения написанного. Главное здесь "different datatypes".


В контексте обсуждения главное как раз не different datatypes, а subtypes и signatures. Но я об этом уже говорил.

VD>>>Я уже говорил, что аналог рефлексии был доступн в КОМ который моно было реализовывать на С++.


E>>Да, но не полной рефлексии, как в Java или Ruby. А только рефликсии для того, за что ты заплатил.


VD>А какая разница то?


Принципиальная: рефлексия для любого типа или рефлексия только для того, что я явно заказал.

VD>И вообще, откровенно говоря использование всех этих предрассудков в качестве аргументации и постоянное переключение с руби на С++ уже надоело. Ты себя уже убдил. Явно аргументы и информация тебе не нужна. Если что еще раз переключишся с С++ на Руби.


Обязательно, т.к. ты переключаешься с C++ на COM. Хотя COM -- к C++ не имеет никакого отношения. В Java/C#/Ruby для рефлексии мне не нужны ни COM, ни CORBA. А в C++ -- нужны. И в этом разница. А доступна рефлексия в этих языках именно из-за того, что язык занимается метаинформацией, а не сторонняя библиотека или технология.

VD>В общем, кончай юлить. Ты заявил что для динамической загрузки нжен байткод и рантайм. Это не соотвествует действительности и ты это знашь. Что еще обсуждать?


Я заявил:

А использование байт-кода и виртуальной машины в Java позволило применять такие механизмы, как динамическая загрузка кода и интанцирование объектов по имени класса.


В C++ нет механизма инстанцирования объекта любого произвольного класса просто по имени класса. НЕТ.
Это становится возможным при использовании 3rd party инструментов, таких, как COM/CORBA или моего ObjESSty. И то, только для тех типов, которые были явно перечислены. Но в самом C++ такой возможности нет.

А в Java/Ruby есть изначально.

VD>>>Извини, но явно не понимашь того что такое компонентность и ее поддержка языком. Простой пример. Попробуй создать два типа в разных модулях (ну, например длл-ках). Обе ДЛЛ-ки должны быть скомпилированы без знания о наличии второй. То есть никакой код из одной не должен быть доступен при компиляции другой. Один из типов должен быть шаблоном. Так вот. Попробуй теперь написать третий модуль (предположим ЕХЕ) который загрузит два предыдущих, возмет из одного шаблон, из другого второй тип и создаст экземляр шаблона параметром типа которого будет указан тип из второго модуля. Вот кога неуправляемый С++ это сможет сделать без костылей вроде КОМ-а, тогда можно будет делать такие утверждения.


E>>А расскажи мне, как третий модуль возьмет два типа из двух других модулей? Просто по имени? Не зная даже, какие интерфейсы они поддерживают?


VD>А это твоя проблема.


Это твоя проблема. Ты не полностью сформулировал задачу.

E>>И ты думаешь, что запись: ((SomeDelegate)process.start).BeginInvoke -- это нормально? Да еще при условии, что SomeDelegat где-то должен быть описан.


VD>Не фантан конечно, но твое предложение в языке присуствует. Ты же говорил, что этого нет и это был бы прорыв. Ты же не сказал, что прорыв был бы если бы в C# упростили синтаксис ассинхронного вызова?


VD>Может все же признать, что был не прав?


Признаю, что не знал, что есть асинхронные делегаты.

Но асинхронные делегаты и асинхронный вызов метода -- это, имхо, разные вещи.

С делегатом я сохраняю куда-то ссылку на объект и ссылку на метод (создаю делегат) и вручную вызваю BeginInvoke. Все это вручную.

Когда же я говорил про асинхронные методы, я подразумевал, что все эти вещи за меня сделает компилятор -- мне нужно только вызвать метод и все. Очень похоже на то, что Саттер предлагает в concurrent C++.

Если ты не видишь разницы между такими подходами, то вот аналогия: в С/Oberon виртуальные методы можно эмулировать вручную за счет ручного управления vtbl. А в ОО языках программисту это не нужно -- сам язык такими низкоуровневыми вещами занимается.

VD>Я так понимаю в большом коллективе ты Руби еще не применял? Боюсь, что через некоторое время твоя любовь к уткам может резко уменьшиться.


Очень возможно. Мне так же кажется, что Ruby, как и C++ -- язык для небольших команд. Так же, как и Smalltalk.

E>> А вот моменять реализацию чего-нибудь на ходу, не останавливая работающую систему -- это круто. Вот так в on-line баги фиксить, без остановки сервиса!


VD>Гы. Ты из какого века? В VC еще в 6.0 была возможность менять код без перезапуска отлаживаемого процесса.


Ты говоришь про отладчик и про код, который был со специальной отладочной информацией скомпилирован.
Я же говорю про production систему.

VD>Это рефлексия и т.п. Там проверка безопастности работает. Это тебе не файлик с исходником в дирректорию бросить.


E>>Нет, я надеюсь, что у Ruby круг пользователей будет раза в три пошире, чем у Smalltalk-а.


VD>Похоже ты уже прав. Глянул тут на количество проектов на sourceforge.net:

VD>Smalltalk (56 projects)
VD>Ruby (377 projects)
VD>Круче Smalltalk только D и Оберон :
VD>Oberon (0 projects)
VD>D (24 projects)
VD>Оберон даже был обойден Модулой:
VD>Modula (7 projects)

У Rubyist-ов sourceforge не в почете. Есть www.rubyforge.org и Ruby Application Archive. Основные проекты там хостятся.

VD>Вот только одно "но". Встретить проект создающийся исключительно на руби трудно. Обычно Руби сочетается с Явой или С++. Так что язык явно не GPL.


Это тебе кажется. У тех, кто Ruby пользуется по этому поводу нет ни сомнений, ни комплексов.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[19]: Следующий язык программирования
От: Зверёк Харьковский  
Дата: 08.10.05 09:19
Оценка: :)
Здравствуйте, eao197, Вы писали:

E>Ну да бог с ним. Меня ты не переубедил, а правду пускай историки ищут.


Вот спасибо. Вот уж спасибочки...
FAQ — це мiй ай-кью!
Re[11]: Следующий язык программирования
От: ansi  
Дата: 08.10.05 09:54
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Я таких не видел. Толку от сверхпроизводительности, если пользоваться неудобно и падает каждые десять минут, притом еще и доделан будет завтра. Все в конечном счете сводится к экономической эффективности, а ее можно оценить. И де факто железки сейчас значительно дешевле, нежели софт (если только софт, конечно, не тиражируется десятками миллионов копий).


А с чего вдруг так сразу эффективность подразумевает глючно???
new RSDN@Home(1.2.0, 618) << new Message(); std::head::ear << "Pantera — Walk";
Re[19]: Следующий язык программирования
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.10.05 10:19
Оценка: +1
Здравствуйте, eao197, Вы писали:


E>Не-а. Это распространенная догма. Главное противоречие в нем, что "отсылка" это асинхронное понятие, а "вызов" -- это синхронное. Когда мы приравниваем отсылку вызову, то для реализации асинхронного взаимодействия приходится придумывать грабли вроде BeginInvoke/EndInvoke или active в очередном прожекте Саттера.

А это прямо у Кея так и сказано? Т.е. он имел в виду именно асинхронную отсылку? Если честно, то очень сомневаюсь.
Потому, что такая модель необходимо требует наличия каких-то способов синхронизироваться (либо чудовищно усложнять реализацию каждого объекта). Поскольку порядок доставки сообщений никак не будет регламентирован.

E>Я ожидал, что после моего примера такие упреки появятся -- мол дизайн должен быть правильный. А не правильный, так рефактори. Предсказуемо, скучно.


E>А ситуация такая: deliver_sm_t и data_sm_t -- это инкапсуляция разных PDU. Между ними есть небольшие пересечения по функциональности. Оба они is-a PDU. Но deliver_sm_t не есть data_sm_t и наоборот.

Угу. Понятно.
E>В одном из приложений мне потребовалось унифицированная обработка как deliver_sm_t, так и data_sm_t. И шаблоны C++ это позволили мне сделать без изменения первоначальной иерархии классов PDU.
Надо полагать, речь идет о явной специализации? Или у тебя у двух PDU cлучайно совапали наборы некоторых методов?
E>Если же следовать "хорошему" дизайну, то как только такая унифицированная обработка потребовалась, то нужно делать рефакторинг и вводить интерфейс deliver_and_data_sm_base_t, а затем реализовать этот интерфейс в deliver_sm_t и data_sm_t.
Нет, почему. Это может вообще быть недоступно — оба класса прибыли в бинарном подписанном виде.
Тогда мы вводим вместо шаблона с явным специализациями интерфейс, в котором ровно утиный набор методов. И делаем две реализации, врапающих твои deliver_sm_t, так и data_sm_t. Объем кода — совершенно аналогичный. Ну, разве что шарп покомпактнее за счет сведения h и сpp

E>Если в другой задаче мне потребуется унифицированная обработка deliver_sm_t, data_sm_t и submit_multi_sm_t (в которых пересечения так же есть), то мне нужно будет сделать очередной рефакторинг и ввести интерфейс

Зачем? Интерфейс у нас уже есть. Осталось дописать ровно одну реализацию.
E>Вот только C++ шаблоны позволяют решать подобные задачи легко и без лишних усилий (со статической типизацией при этом).
Вот этот момент мне принципиально непонятен. Откуда берутся лишние усилия?
Можно привести пример, так чтобы мы сравнили килокалории?
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[12]: Следующий язык программирования
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.10.05 10:28
Оценка: 1 (1) +2
Здравствуйте, ansi, Вы писали:
A>А с чего вдруг так сразу эффективность подразумевает глючно???
Ну как же? Вот, давеча, наш поборник эффективности Pavel Dvorkin наглядно продемонстрировал, как он собирается конкатенировать строки при помощи sprintf. При этом он заботливо вставил в этот код уязвимость к переполнению буфера.

Во-первых, оптимизированный код как правило сложнее неоптимизированного (обратное, вообще говоря, неверно). А количество багов на строчку — примерно константа.
Во-вторых, возникает искушение в целях оптимизации пожертвовать подстиланием соломки. И там, где неоптимизированный код имеет шанс благополучно опасную ситуацию обработать, оптимизированный честно сделает что сказали.

Не спорю, что не всегда это так. Целенаправленное улучшение качества кода имеет тенденцию уменьшать глючность и повышать быстродействие. Однако при ограниченных ресурсах у нас неизбежно приходится чем-то из них жертвовать.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: Следующий язык программирования
От: Dyoma Россия http://www.livejournal.com/users/dyomap/
Дата: 08.10.05 11:22
Оценка:
Здравствуйте, VladD2, Вы писали:

D>>Ну интерпретируемость ни сколько не мешает гипотетическим возможностям. Хочешь exe получить — засунь в него интрепретатор и исходник этим, при желании, можно даже микроконтроллеры прошивать


VD>Дело не в ЕХЕ. Дело в пригодности для разработки больших проектов кторые могут требочать еще и высокой производительности. Есть мнение что интепретаторы плохо для этого подходят, и почему-то это мнение разделяю.


Ну если продолжать твою мысль о связи между производительностью то получится, что есть один вид универсальных языков программирования — ассемблеры , ну может еще C++, но уже с натяжкой...
А если серьезно, то я думаю в твоем утверждение ключевые слова "большой проект". Т.е. язык должен позволять писать понятный код и разбивать проект на независимые части.

Dyoma
ALMWorks
http://deskzilla.com/
Re[13]: Следующий язык программирования
От: ansi  
Дата: 08.10.05 11:31
Оценка: +2
Здравствуйте, Sinclair, Вы писали:

A>>А с чего вдруг так сразу эффективность подразумевает глючно???

S>Ну как же? Вот, давеча, наш поборник эффективности Pavel Dvorkin наглядно продемонстрировал, как он собирается конкатенировать строки при помощи sprintf. При этом он заботливо вставил в этот код уязвимость к переполнению буфера.

Да, Павел конечно нашумел Что касается его заявлений, то я с ними согласен в смысле фразы dont't pessimize prematurely. Иначе говоря "думай и понимай, что ты пишешь". Вся проблема, о которой Павел говорил, то в том, что зачастую люди не думают или не понимают, что они пишут (или, скорее, не хотят думать), а попросту педалят код. Лично я никогда не позволяю себе расслабится настолько сильно...
Что касается примера, то, надеюсь, это чтобы, так сказать, мысль показать, а не реальный кусок некой системы

S>Во-первых, оптимизированный код как правило сложнее неоптимизированного (обратное, вообще говоря, неверно). А количество багов на строчку — примерно константа.

Почти согласен Но тут дело в чем: оптимизированный код действительно сложнее нормального кода, но нормальный код как правило не сложнее пессимизированного, а то и вовсе проще, на мой взгляд.

S>Во-вторых, возникает искушение в целях оптимизации пожертвовать подстиланием соломки. И там, где неоптимизированный код имеет шанс благополучно опасную ситуацию обработать, оптимизированный честно сделает что сказали.

Хм. Такую ситуацию я могу представить себе при ну уж очень жестокой оптимизации, что в настоящее время, наверное, большая редкость. Жертвуют "подстилкой", насколько я понимаю, в основном из-за банальной лени (сам грешен, но перебарываю себя всегда ).

S>Не спорю, что не всегда это так. Целенаправленное улучшение качества кода имеет тенденцию уменьшать глючность и повышать быстродействие. Однако при ограниченных ресурсах у нас неизбежно приходится чем-то из них жертвовать.

Правило "два из трех"? Ну да. Только на мой взгляд, не составляет большого труда писать сразу нормальный код, вместо педальщины.
new RSDN@Home(1.2.0, 618) << new Message(); std::head::ear << "Pantera — Walk";
Re[13]: Следующий язык программирования
От: Cyberax Марс  
Дата: 08.10.05 11:43
Оценка:
Sinclair wrote:

> A>А с чего вдруг так сразу эффективность подразумевает глючно???

> Ну как же? Вот, давеча, наш поборник эффективности Pavel Dvorkin
> наглядно продемонстрировал, как он собирается конкатенировать строки
> при помощи sprintf. При этом он заботливо вставил в этот код
> уязвимость к переполнению буфера.

Мой код конкатенации не хуже кода Павла, а уязвимостей в нем нет. Причем
вроде бы и каких-то сложных вещей в нем тоже нет.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[20]: Следующий язык программирования
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 08.10.05 11:50
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, eao197, Вы писали:



E>>Не-а. Это распространенная догма. Главное противоречие в нем, что "отсылка" это асинхронное понятие, а "вызов" -- это синхронное. Когда мы приравниваем отсылку вызову, то для реализации асинхронного взаимодействия приходится придумывать грабли вроде BeginInvoke/EndInvoke или active в очередном прожекте Саттера.

S>А это прямо у Кея так и сказано? Т.е. он имел в виду именно асинхронную отсылку? Если честно, то очень сомневаюсь.

Я не знаю, как у Кея сказано.

Просто, исходя из смысла слов "отсылать" (send) и "вызывать" (call) не следует считать, что "отсылка" == "вызову". А в большинстве языков так и есть, причем изменить ничего нельзя.

S>Потому, что такая модель необходимо требует наличия каких-то способов синхронизироваться (либо чудовищно усложнять реализацию каждого объекта). Поскольку порядок доставки сообщений никак не будет регламентирован.


Не правда. Мы используем у себя агентно-ориентированный фреймворк, который работает исключительно на принципах асинхронной отсылки сообщений. И порядок доставки там регламентируется очень просто: хронологический + влияние приоритета.

E>>А ситуация такая: deliver_sm_t и data_sm_t -- это инкапсуляция разных PDU. Между ними есть небольшие пересечения по функциональности. Оба они is-a PDU. Но deliver_sm_t не есть data_sm_t и наоборот.

S>Угу. Понятно.
E>>В одном из приложений мне потребовалось унифицированная обработка как deliver_sm_t, так и data_sm_t. И шаблоны C++ это позволили мне сделать без изменения первоначальной иерархии классов PDU.
S>Надо полагать, речь идет о явной специализации? Или у тебя у двух PDU cлучайно совапали наборы некоторых методов?

Нет, в некоторых случаях специализация есть, но не везде. А у двух PDU действительно совпали наборы некоторых методов. Поскольку deliver_sm_t и data_sm_t могут использоваться для одних и тех же целей.

E>>Если же следовать "хорошему" дизайну, то как только такая унифицированная обработка потребовалась, то нужно делать рефакторинг и вводить интерфейс deliver_and_data_sm_base_t, а затем реализовать этот интерфейс в deliver_sm_t и data_sm_t.

S>Нет, почему. Это может вообще быть недоступно — оба класса прибыли в бинарном подписанном виде.

Именно.

S>Тогда мы вводим вместо шаблона с явным специализациями интерфейс, в котором ровно утиный набор методов. И делаем две реализации, врапающих твои deliver_sm_t, так и data_sm_t. Объем кода — совершенно аналогичный. Ну, разве что шарп покомпактнее за счет сведения h и сpp


На C++ можно такой же прием применить: ввести интерфейс и врапперы вокруг классов. По объему это будет ~ шарповскоми или Java-вскому. Мне не нравится, что нам вообще нужно эти интерфейсы и врапперы вводить. Обобщенное программирование (которое на сигнатурах базируется) позволяет этого не делать.

E>>Если в другой задаче мне потребуется унифицированная обработка deliver_sm_t, data_sm_t и submit_multi_sm_t (в которых пересечения так же есть), то мне нужно будет сделать очередной рефакторинг и ввести интерфейс

S>Зачем? Интерфейс у нас уже есть. Осталось дописать ровно одну реализацию.

Нет, я имел ввиду, что при добавлении submit_multi_sm_t набор методов в интерфейсе потребуется сократить.

E>>Вот только C++ шаблоны позволяют решать подобные задачи легко и без лишних усилий (со статической типизацией при этом).

S>Вот этот момент мне принципиально непонятен. Откуда берутся лишние усилия?

Если специализации шаблонов нет (а это часто бывает), то лишние усилия заключаются как раз в выделении общего интерфейса и врапперов.

S>Можно привести пример, так чтобы мы сравнили килокалории?


Вряд ли, там код объемный. А я уже с Владом забодался по этому поводу спорить.
Но что-то похожее мы обсуждаем здесь: Re[9]: Утиные истории vs ООП?
Автор: eao197
Дата: 08.10.05
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[14]: Следующий язык программирования
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.10.05 13:09
Оценка: 1 (1) +3 :)
Здравствуйте, Cyberax, Вы писали:
C>Мой код конкатенации не хуже кода Павла, а уязвимостей в нем нет. Причем
C>вроде бы и каких-то сложных вещей в нем тоже нет.
Совершенно верно. Но ты и не бегаешь с фонарем и криками "долой непроизводительность!" Ты почему-то не стал заниматься хаками со спринтфом (за само использование которого без санкции главного архитектора надо давать три года программирования на клиппер'87), и уж тем более не пытался доказать компилеру, что ты лучше него знаешь структуру конвеера x86.
Это и есть нормальный подход к производительности. Плохо то, что в погоне за тактами можно привыкнуть писать именно такие ужасы. Меня это пугает ничуть не меньше, чем перспктива "потерять способность писать эффективно". it's much easier to make correct code run fast, than to make fast code correct. Надо писать в первую очередь корректный и читабельный код.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[21]: Следующий язык программирования
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.10.05 13:09
Оценка:
Здравствуйте, eao197, Вы писали:

E>Просто, исходя из смысла слов "отсылать" (send) и "вызывать" (call) не следует считать, что "отсылка" == "вызову". А в большинстве языков так и есть, причем изменить ничего нельзя.

Ну мы тождество то и не утверждаем. Но этот спор начинает напоминать средневековую схоластику. "Если в слове send сделать 4 ошибки, то получится слово call".

Можно трактовать и так и эдак. Асинхронная отправка — это односторонний процесс, fire and forget. Не спорю, такая модель вполне имеет право на существование. Дийкстра вообще считал, что это лучший способ обеспечения параллелизма.

Но по традиции, в современном программировании предпочитают поддерживать концепцию вызова — т.е. посылки сообщения, совмещенной с ожиданием результата.

E>Не правда. Мы используем у себя агентно-ориентированный фреймворк, который работает исключительно на принципах асинхронной отсылки сообщений. И порядок доставки там регламентируется очень просто: хронологический + влияние приоритета.

При случае прочитаю, но пока я не могу себе представить. Тут что-то одно — или асинхронность, или детерминированный порядок
Пример:
объект А обрабатывает какое-то сообщение. В рамках этой обработки он отправил объекту B сообщение b, а объекту С — сообщение с.
Ок, принцип причинности, все дела. Пока объекты B и С обрабатывают эти сообщения внутри себя, им по барабану концепции одновременности. Они были в каких-то состояниях на момент прихода сообщений, а потом перейдут в какие-то другие состояния. Нам неважно даже, в каком порядке они получат сообщения b и c.

Но чу! В рамках обработки этих сообщений они послали одному и тому же объекту D сообщения d1 и d2. И вот тут начинается пропасть: в каком порядке объект D получит эти сообщения?
Вариант 1: в недетерминированном. Тогда, для обеспечения логической целостности, сообщения должны быть коммутативны. т.е. D->d1->d2 должно в точности совпадать c D->d2-d1. Любой, кто пробовал в один вечер пить пиво и водку, знает, что далеко не всегда удается достичь такой гармонии.
Вариант 2: в детерминированном. Определяться он может только порядком отправки сообщений a и b. Но это означает, что С не имеет права начать рассылку сообщений до того, как B ее закончит! А какая же это к лешему асинхронность? У нас все методы выполняются по очереди. Вот и получается, что мы все едино вынуждены ждать подтверждения от объекат B о том, что путь чист, а уж потом посылать сообщение С.

E>Нет, в некоторых случаях специализация есть, но не везде. А у двух PDU действительно совпали наборы некоторых методов.

Ну вот это я вообще не понимаю. Видишь ли, я не верю в странные совпадения. Если их писали разные люди, то с вероятностью 100% методы не будут совпадать если не сигнатурой, так семантикой. А если одни и те же, и архитектор не даром пьет свое пиво по пятницам, то там 99% уже задекларированы нужные интерфейсы. Все — сугубо имхо.
E>Поскольку deliver_sm_t и data_sm_t могут использоваться для одних и тех же целей.
E>На C++ можно такой же прием применить: ввести интерфейс и врапперы вокруг классов. По объему это будет ~ шарповскоми или Java-вскому. Мне не нравится, что нам вообще нужно эти интерфейсы и врапперы вводить.
А куда ты денешься, с подводной лодки?
E>Обобщенное программирование (которое на сигнатурах базируется) позволяет этого не делать.
Извини, в случайные совпадения я никак не верю. И вероятность их экспоненциально падает с ростом длины сигнатуры.
Вот, к примеру, все потоки в шарпе имеют совершенно одинаковый метод Read. И это правильно и здорово. Но это никак не случайно. Это предусмотренная конструкцией вещь. И все разработчики чего-то с потоковым интерфейсом читают инструкции, и наследуются от Stream. А если нет — то бдительный архитектор должен пойти и настучать штангенциркулем по пальцам.

И я, как архитектор, не поверю, если мне покажут код, который работает, опираясь на случайное наличие в классе метода типа send_io_control_packed.

S>>Зачем? Интерфейс у нас уже есть. Осталось дописать ровно одну реализацию.


E>Нет, я имел ввиду, что при добавлении submit_multi_sm_t набор методов в интерфейсе потребуется сократить.

Теперь я уже совсем не понимаю. Зачем? Все наоборот. Начнем сначала:
1. У нас внезапно возникла необходимость обрабатывать объекты двух принципиально несвязанных классов единым образом.
2. Мы вводим для этого класс-обработчик (забъем пока на свободные функции).
3. И вот тут мы стоим на распутье:
3.1. Сделать его шаблонным. Внутри этого шаблона будут происходить обращения к некоторым (предположительно одноименным) мемберам обоих классов.
3.2. Декларировать явный интерфейс, который содержит ровно тот минимальный контракт, который необходим обработчику. Совершенно необязательно пихать в него все общие мемберы обоих классов-жертв!
4.2 При добавлении третьего класса, нам не придется перерабатывать интерфейс. А зачем? Ведь он уже и так покрывает всю нужную обработчику функциональность. Все, что нужно — это сделать несложную реализацию. В плюсах с этим, насколько я помню, похуже — там придется явно писать код отображения мемберов в вызовы предка. В шарпе это происходит автоматически.
Если же третий класс все же чем-то отличается от первых двух, то придется делать соответствующую специализацию.


E>Если специализации шаблонов нет (а это часто бывает)

У меня не так много опыта. Приведи, пожалуйста, реальный пример случайного совпадения сигнатур вместе с семантикой.
E>, то лишние усилия заключаются как раз в выделении общего интерфейса и врапперов.
Видишь ли, на шарпе враппер стоит не намного дороже инстанцирования шаблона. Если, конечно, класс не оказался запечатанным. Иначе, конечно, придется немножко попотеть.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[22]: Следующий язык программирования
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 08.10.05 13:58
Оценка:
Здравствуйте, Sinclair, Вы писали:

Продолжим разговор про синхронность и асинхронность.

S>Можно трактовать и так и эдак. Асинхронная отправка — это односторонний процесс, fire and forget. Не спорю, такая модель вполне имеет право на существование. Дийкстра вообще считал, что это лучший способ обеспечения параллелизма.


S>Но по традиции, в современном программировании предпочитают поддерживать концепцию вызова — т.е. посылки сообщения, совмещенной с ожиданием результата.


В том то и дело, что традиция эта в таких языках, как C++, Java, C# и пр. зашита намертво. Если нам в 5% случаев потребуется именно fire and forget, то сделать это в том же самом синтаксисе, что и обычный call, мы уже не сможем. А вот если бы смогли, это бы я и считал прорывом.

E>>Не правда. Мы используем у себя агентно-ориентированный фреймворк, который работает исключительно на принципах асинхронной отсылки сообщений. И порядок доставки там регламентируется очень просто: хронологический + влияние приоритета.

S>При случае прочитаю, но пока я не могу себе представить. Тут что-то одно — или асинхронность, или детерминированный порядок
S>Пример:
S>объект А обрабатывает какое-то сообщение. В рамках этой обработки он отправил объекту B сообщение b, а объекту С — сообщение с.
S>Ок, принцип причинности, все дела. Пока объекты B и С обрабатывают эти сообщения внутри себя, им по барабану концепции одновременности. Они были в каких-то состояниях на момент прихода сообщений, а потом перейдут в какие-то другие состояния. Нам неважно даже, в каком порядке они получат сообщения b и c.

S>Но чу! В рамках обработки этих сообщений они послали одному и тому же объекту D сообщения d1 и d2. И вот тут начинается пропасть: в каком порядке объект D получит эти сообщения?

S>Вариант 1: в недетерминированном. Тогда, для обеспечения логической целостности, сообщения должны быть коммутативны. т.е. D->d1->d2 должно в точности совпадать c D->d2-d1. Любой, кто пробовал в один вечер пить пиво и водку, знает, что далеко не всегда удается достичь такой гармонии.
S>Вариант 2: в детерминированном. Определяться он может только порядком отправки сообщений a и b. Но это означает, что С не имеет права начать рассылку сообщений до того, как B ее закончит! А какая же это к лешему асинхронность? У нас все методы выполняются по очереди. Вот и получается, что мы все едино вынуждены ждать подтверждения от объекат B о том, что путь чист, а уж потом посылать сообщение С.

А теперь расскажи, если не сложно, как ты видишь здесь детерминизм в виде синхронных вызовов, если объекты B, C и D должны работать на разных нитях. Во что все это выльется?
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[22]: Следующий язык программирования
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 08.10.05 13:58
Оценка:
Здравствуйте, Sinclair, Вы писали:

E>>Нет, в некоторых случаях специализация есть, но не везде. А у двух PDU действительно совпали наборы некоторых методов.

S>Ну вот это я вообще не понимаю. Видишь ли, я не верю в странные совпадения. Если их писали разные люди, то с вероятностью 100% методы не будут совпадать если не сигнатурой, так семантикой. А если одни и те же, и архитектор не даром пьет свое пиво по пятницам, то там 99% уже задекларированы нужные интерфейсы. Все — сугубо имхо.

Совпадения не случайные (по-моему про случайность я и не говорил). Есть два типа PDU -- deliver_sm и data_sm. Они могут применятся для одной и той же задачи: доставки входящего SMS. Т.к. задача одинаковая, то и многие параметры у этих PDU одинаковые. Но deliver_sm не есть data_sm, т.к., в отличии от data_sm, deliver_sm применяется только для входящих SMS. А data_sm может применятся и для исходящих. В свою очередь, data_sm, не есть deliver_sm, т.к. у deliver_sm больше параметров. Вот упрощенные спецификации:
class deliver_sm_t
    {
    public :
        const std::string & service_type() const;

        const oess_1::uchar_t & source_addr_ton() const;
        const oess_1::uchar_t & source_addr_npi() const;
        const std::string & source_addr() const;

        const oess_1::uchar_t    & dest_addr_ton() const;
        const oess_1::uchar_t    & dest_addr_npi() const;
        const std::string & dest_addr() const;

        const oess_1::uchar_t & esm_class() const;

        const oess_1::uchar_t & protocol_id() const;

        const oess_1::uchar_t & priority_flag() const;

        const std::string & schedule_delivery_time() const;

        const std::string & validity_period() const;

        const oess_1::uchar_t & registered_delivery() const;

        const oess_1::uchar_t & replace_if_present_flag() const;

        const oess_1::uchar_t & data_coding() const;

        const oess_1::uchar_t & sm_default_msg_id() const;

        const std::string &    short_message() const;
    };

class data_sm_t
    {
    public :
        const std::string & service_type() const;

        const oess_1::uchar_t & source_addr_ton() const;
        const oess_1::uchar_t & source_addr_npi() const;
        const std::string & source_addr() const;

        const oess_1::uchar_t    &    dest_addr_ton() const;
        const oess_1::uchar_t    & dest_addr_npi() const;
        const std::string & dest_addr() const;

        const oess_1::uchar_t & esm_class() const;

        const oess_1::uchar_t & registered_delivery() const;

        const oess_1::uchar_t & data_coding() const;
    };


Пересечения методов не случайно. Однако, я не думаю, что имеет смысл объединять общие методы классов deliver_sm_t и data_sm_t в какой-то интерфейс. Хотя бы потому, что часть этих методов присутствуют и в других типах PDU. Например, broadcast_sm (source_addr_ton, source_addr_npi, source_addr, sm_default_msg_id), cancel_sm (source_addr*, dest_addr*). Если идти по такому пути, то придется плодить массу мелких интерфейсвов (pdu_with_source_addr_t, pdu_with_dest_addr_t, pdu_with_data_coding_t, ...). Но зачем? Способы обработки PDU могут быть разными. Где-то, например, только поле service_type контролируется, где-то только data_coding.

E>>Поскольку deliver_sm_t и data_sm_t могут использоваться для одних и тех же целей.

E>>На C++ можно такой же прием применить: ввести интерфейс и врапперы вокруг классов. По объему это будет ~ шарповскоми или Java-вскому. Мне не нравится, что нам вообще нужно эти интерфейсы и врапперы вводить.
S>А куда ты денешься, с подводной лодки?

Ну в C++ можно на шаблонах, без врапперов
Да и в Ruby так же

E>>Нет, я имел ввиду, что при добавлении submit_multi_sm_t набор методов в интерфейсе потребуется сократить.

S>Теперь я уже совсем не понимаю. Зачем?

Мы наверное говорим о разных use-case. Я имел ввиду, что в одном модуле приложения потребовалось как-то обрабатывать и deliver_sm, и data_sm. А во втором модуле -- как deliver_sm, data_sm, так и submit_multi_sm. Две разных, независимых задачи. В разных модулях.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[13]: Следующий язык программирования
От: Cyberax Марс  
Дата: 08.10.05 15:03
Оценка:
Andrei N.Sobchuck wrote:

> C>А вообще, идея с бинарным репозиторием исходных файлов, с которым

> IDE работает напрямую, была опробована в VisualAge for Java. Успешно
> провалилась
> Так дело не бинарности/текстовости. А в том, что единицей
> версионирования является файл, а не функция (или еще какая часть AST).

Так VAJе ведь именно так и было — пользователь работал на уровне
элементов AST.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.