?

Log in

No account? Create an account

Предыдущий пост поделиться Следующий пост
Священная война
lex_kravetski

 

Про Haskell мы с товарищами уже несколько раз реально перетёрли. И про удобства, и про сравнение с объектными языками. Сейчас назрела внутренняя необходимость (то бишь, злость взяла) перетереть на баянистую тему: C++ vs Java.

Для справки: на C++ я программировал лет десять. После этого я благополучно децл сменил область деятельности и перешёл на Java. Из этого всем должно быть очевидно, что оба языка я хорошо знаю и понимаю (кому не очевидно, тот сам виноват). Однако же пару дней назад пришлось-таки снова написать всякого на C++. Что вызвало нехилое раздражение.

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

И так во всём. Чуть где нужно что-то очевидно стандартное – его нет. Зато есть что-то очень-очень гибкое, с помощью чего это стандартное следует собирать. Причём, началось это очень давно. В тот самый момент, когда разработчики С решили вдруг, что строки вполне можно встроить в виде char*. Да чего там – в тот момент, когда они поняли, что с помощью массивов вообще всё что угодно можно сгенерить. Они были правы, но их правота вылилась в мега-кучи ошибок с битой памятью. По опыту, половина ошибок при написании чего-то на C проистекает из-за бития памяти с помощью char*.

Второй мощный шаг – это непредоставление способа просто и наглядно определить длину массива в штуках элементов. Можно, конечно, предположить, что таким образом экономилось место в памяти, но блин, всё равно длина массива в ней хранится, просто нет способа быстро и просто её узнать. Вместо этого надо узнавать размер выделенной памяти и делить его на размер элемента. На деле же – хранить спецпеременную, в которой лежит длина массива. Поскольку, без длины с массивом всё равно сделать почти ничего нельзя.

По счастью, при разработке С++ часть этих недочётов была учтена и в STL всё-таки сделали и вменяемые строки и вменяемые контейнеры. Но С, друзья мои, не умер. Он живёт в обрывках кода, которые до сих пор приходится использовать. Так, например, в WinAPI не стали использовать STL, вместо этого ввели свои типы и очень весёлую форму записи. С указателями, а иногда даже с двойными указателями. Если надо получить набор значений, то изволь заводить буфер под них и сообщать его размер соответствующей функции. Так мега-экономия памяти обернулась её разбазариванием в буферах.

Стоит ли говорить, что для превращения std::string в спецтип WinAPI и обратно, надо писать дополнительный код. Ну а если нужен не WinAPI, а MFC, то там тоже свои классы и тоже нужна конверсия. Казалось бы мелочь – не сделали встроенный тип «строка», однако вон оно как вышло.

Кстати, строки иногда надо превращать в числа, а числа – в строки. Что в этих случаях делается в Java? Да ничего практически. Число в строку превращается само (или явным вызовом встроенного toString()), а обратно парсится встроенными же Integer.parseInt и им подобными. Операция-то очень распространённая, отчего бы её не встроить в С++? Говорят, нельзя. Говорят, каждый программист сам для себя напишет. Вот и пишут.

Самое интересное: кто сходу скажет, что надо написать, чтобы вывести на экран double с той точностью, которая в данном случае есть у числа? Ну, то есть, если double x = 123123.5657356252, то на экран вывелось бы 123123.5657356252?

cout << x; ?

printf("%f", x); ?

Фиг вам, дорогие программисты. Всё это выведет число вовсе не в том виде, в котором хотелось бы. Для одних чисел обрубится дробная часть, другие переведутся в экспоненциальную форму и так далее. Простая до тривиальности задача в С++ имеет совершенно дикие и неочевидные решения. И не каждый джигит сможет до них допетрить.

Зато в printf можно очень гибко задавать формат вывода. Любой формат. Кроме самого простого и очевидного. Точнее, его тоже можно задать, но выглядит это так, что никто не догадается. В общем, чем так согрешила функция «перевести в строку»? Неужели же своей простотой? Я не знаю. Знаю только, что в Java нет никаких проблем с переводом чисел во все стороны. И, кстати, printf там ровно такой же, как в С++. Но им пользуются редко.

Ах да, есть же функции парсинга в С! Как же они называются? fromString? Нет. StringToDouble? Для С++ слишком очевидные названия. Слишком длинные. Наверно str_to_dbl? Тоже нет. Функция называется atof. Такое вот простое и очевидное название. Любой сразу догадается, что функция должна называться именно так. Что интересно, если конверсия не удаётся (вместо «1.2» в строке содержится, например, «Fuck off»), то что будет? Выкинется исключение? Но, увы, это – функция из С, а в С нет исключений. Поэтому функция просто и незамысловато вернёт ноль. Что делает проверку валидности значений весьма нетривиальным занятием – по действиям функции ведь совершенно непонятно, действительно ли ноль был в строке или какое-то левое значение. И как, блин, проверить? Сравнить строку с "0"? А если там было "0.0" или "000.00000"? Фигня получается.

Справедливости ради, надо отметить, что есть функция с более очевидным названием strtod. Но ни та, ни другая не работают с std::string, то есть, опять же нужна конверсия через c_str().

Всё это напоминает мне ситуацию, при которой автомеханику даются средства, с помощью которых можно сделать руль очень замысловатой формы, но круглый руль делать так же тяжело, как звёздообразный. Наверно поклонников звёздообразных рулей это порадует, но рули обычно ведь круглые и их изготовление должно быть наиболее простым. В Java так, в С++ – нет.

Проблема в том, что в С++ отсутствует последовательность. Он сделан на основе С, обладает с ним почти полной совместимостью, отсутствующее в С прикручено к нему изолентой, и, – что самое плохое, – он исповедует свободу во вред – не задаёт стандартов. Отсутствие стандартного подхода ко всему, полагание на «программист сам додумается» приводит к разнобою даже внутри самого языка, не говоря уже про сторонние библиотеки. С++ не задаёт даже стандартных способов именования. Поэтому в разных программах встречаются совершенно разные способы. У кого-то венгерская нотация, у кого-то всё идёт через подчёркивание, у кого-то вообще никакой. Свобода, блин. Программиста не притесняют. Но такая свобода хороша, когда программист находится в вакууме и всё его общение с внешним миром сводится к вбрасыванию туда экзешников. Увы, обычно это не так. Программист обычно пользуется чужими библиотеками и чужим же кодом. В результате Java-код и Java-библиотеки в 99% случаев имеют один и тот же стиль именования и даже фигурные скобки там проставлены одинаково. Чужой Java-код не портит своего. А вот в случае С++ всё сразу идёт вразнос. В одной библиотеке функции называют в виде MyFunc, в другой – My_Super_Func, в третей – mymegafunc, ваш коллега любит венгерскую нотацию, а вы сами совершенно справедливо уважаете нэйминг из Java. При этом одни требуют указатели, другие – ссылки, а третьи – ссылки на указатели. В вашем же коде всё это превращается в

 

int myValue = mymegafunc(**My_Super_Func(&MyFunc(*m_piValue));

 

Смотришь на всё это и думаешь «да где тут что вообще?!!»

Вот такая она – свобода. Людям её только дай... Стандарты, блин, руля́т.

Вообще в С++ крайне тяжело назвать то, что там сделано лучше, чем в Java. До версии Java 1.4 в С++ лучше было наличие шаблонов. Однако в Java 1.5 появились дженерики, которые шаблоны даже превосходят. Последний плюс уверенно ушёл в прошлое. Ах да, в С++ ещё можно объявить указатель на функцию. Что временами удобно, но имеет такой синтаксис, что за ним надо каждый раз лезть в справочник. Не верите? Ну напишите тогда не подглядывая указатель на константную функцию класса A с параметром int* и её вызов у указателя на объект класса. Я лично такие вещи писал раз триста, но так и не запомнил.

Кстати, в С++ есть и ещё одна полезная штука – возможность передать константный объект и объявить константную функцию. Вот этого в Java пока не сделали. Жаль. Итого один плюс против разливанных морей минусов.

Что меня реально вспарило при временном возвращении к С++, так это долбанные хэдеры. Тут я реально не понимаю, нафига их вообще ввели. Может, предполагалось, что сорсы к хэдерам можно будет подменять? Но, мой бог, зачем? Никто же этим никогда не пользуется. С чего бы тогда код не писать прямо там, где объявляются функции? Загадка, блин, природы. Точнее, загадка человеческой мысли.

Нет, я, конечно, знаю официальную версию: хэдеры нужны, чтобы пользоваться скомпилированными уже библиотеками. Но в Java ведь тоже библиотеки уже скомпилированы. Ну хоть бы тогда сделали что ли автогенерацию этих самых хэдеров при компиляции...

Хэдеры же, кроме необходимости объявлять в одном месте, а писать в другом, влекут за собой ещё одну болезнь С++ – кучи мусора. Выражающиеся в проверках того, что хэдер подключен ровно один раз. Ну да, те самые #ifndef и так далее. Стандартные шаманские строки, которые всех так сильно задолбали. Которые содержатся в каждом хэдере, поскольку далеко не все знают, что можно написать не менее шаманское #pragma once. Но даже с прагмой вопрос остаётся открытым: а какого хрена это одноразовое включение не встроено сразу в язык? Чего бы такого мы потеряли, если бы хэдер включался ровно один раз без нашего вмешательства? Ответа нет. Поскольку ничего бы мы не потеряли. Просто в С++ модно писать мусорный код. В С++ – это элемент стиля. Который ничего не даёт, но очень круто выглядит.

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

Ещё неприятно поразила необходимость писать инклюды вручную. Это, конечно, особенность не языка, а оболочки, но ведь неспроста наверно в оболочках Java импорты включаются автоматически, а в оболочках С++ их надо вписывать руками, хотя и с подсказками компьютера. Печаль сего не в том, что тяжело эту строчку набрать, а в том, что тяжело вспомнить, в какой именно библиотеке лежит нужная функция. В результате приходится постоянно лезть в help.

Кстати, в Java проблема хэлпа тоже была решена универсальным способом – хэлп содержится ровно там, где код. То есть, комментарии к коду являются и хелпом к нему. Некоторые оболочки С++ тоже показывают комментарии во всплывающих подсказках, но без стандарта это – полумера. Никто ведь не знает, в какой форме будет написан комментарий тем или иным программистом. Да и ключевых слов для комментариев не предусмотрено.

В Java разработчики уверенно забороли практически все болезни вдохновлявшего их языка. Во-первых, отказались от статичности и сделали язык дорабатываемым. Во-вторых, как уже было сказано, документацию скрестили с кодом и слили объявления с реализациями. В-третьих, убрали долбанные указатели, заменив их ссылками (ссылкам разрешили принимать нулевое значение – в С++ отсутствие этого очень сильно напрягает). В-четвёртых, – хотя тут спорно, – встроили сборщик мусора. С ним немного медленнее, зато 90% проблем и ошибок исчезли сами собой. В-пятых, ввели стандарты именования. Пусть негласно, но ввели. В-шестых, встроили объект «строка» в язык и научили все объекты преобразовываться в него. В-седьмых, трэды опять же встроили в язык и встроили в него же все механизмы работы с трэдами. Всё перечисленное офигенно удобно. Хотя при слове Java у большинства людей всплывает в мыслях исключительно сборщик мусора, это далеко не единственное преимущество.

Далее. В Java все функции виртуальные. Поэтому программист уже не парится с проблемой: «блин, в этой библиотеке у этого объекта эта функция не виртуальная, и что же мне теперь делать?».

В Java встроен GUI. Причём, не только в виде одной из его возможных реализаций, но и в виде стандартных интерфейсов, которые поддерживают все остальные реализации. GUI не опирается на ресурсные файлы и всё управление им содержится в коде программы. Это – мега-плюс. А второй мега-плюс – GUI в большинстве случаев сам занимается расстановкой и выравниванием элементов. Всё это утомительное жонглирование координатами, которым страдают Builder и MFC, в Java неактуально.

Встроенные библиотеки реализуют практически все стандартные задачи. Причём, таким образом, что гибкость не теряется. То есть, в наличии и максимально гибкие объекты для достижения чего угодно и обёртки над ними для решения стандартных и наиболее часто встречающихся задач. Когда я говорю «практически все», я имею в виду «практически все». Был поражён, например, когда обнаружил в библиотеках работу с midi.

Ну и функции в этих объектах называются так, что по названию понятно, что они делают. И передаются в них ссылки, а не двойные указатели и переменная с длинной массива. Чуть не забыл: массив в Java знает, какая у него длина. И даже может сказать об этом программисту.

Компилятор в Java не даёт забыть про обработку исключений – это тоже большой плюс, хотя с непривычки слегка раздражает. В С++ некоторые функции в редких случаях неожиданно бросали исключение, а программист про это даже не знал. Да, там тоже можно было приписать к функции throws, но можно было и не приписывать, поэтому приписывали далеко не все. В результате программа иногда вылетала в труднообнаружимых местах.

В Java встроена сериализация объектов. Встроены регулярные выражения. Понятно, что всё это можно найти и для С++, но тут даже искать не надо. Более того, контейнеры уже сериализумы – на уровне языка, без дополнительных ухищрений. Во встроенных строках уже все функции работают с регулярными выражениями. Удобство всего этого тем, кто пишет на С++, неочевидно. Зато при возвращении с Java на С++ без этого как без рук. Там, где в Java всё решалось одной строкой, в С++ надо городить нехилый огород или искать в интернете готовые решения. Подчеркну, решения вовсе не узкоспециальных случаев, а стандартных и очень распространённых задач. Давно уже решённых задач, что характерно.

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

Некоторые вещи, конечно, понравились, но это так, по мелочи. Упомянутые константные функции, перегрузка операторов, да и наверно всё. По воспоминаниям есть ещё макросы. Но ими неспроста рекомендуют не пользоваться.

В общем, чтобы я ещё раз сел на этот велосипед, чтобы хоть ещё раз...



Можно сколько угодно расписывать JAva. Но если подойти к вопросу с точки зрения качества конечного результата, то JAva -программы ужасны, и ужасны почти всегда. Они жрут до черта ресурсов (как процессорных, так и памяти) и при этом, как правило, имеют массу проблем.
К сожалению, это общее правило, а не исключения.
Так что.. вижуалБейсик может, тоже удобен для некоторых. Но вот результат.. С ДЖавой почти так же.

Re: Reply to your post...

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

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

> К сожалению, это общее правило, а не исключения.

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

> Так что.. вижуалБейсик может, тоже удобен для некоторых.

На Visual Basic-е писал на протяжении последних трёх месяцев. Он не
то, что не удобен, он адски неудобен. Более уродского языка я очень
давно не видел.

В позапрошлом году был на конференции Sun, вроде они постепенно перетаскивают в Java из C++ всё что можно, включая printf.

Re: Reply to your post...

> В позапрошлом году был на конференции Sun, вроде они постепенно
> перетаскивают в Java из C++ всё что можно, включая printf.

printf было перетащено уже в самой первой версии. А заимствования
хорошего мне очень нравятся. Собственно, С++ тоже можно было бы
поправить, но у него концепция иная, поэтому он всегда будет таким,
какой есть. А в Java сейчас реально не хватает пары вещей -
константных функций и свича по строкам, а не по enum-у (последнего,
впрочем, и в С++ тоже нет).

С нетерпением жду, когда в Java начнут перетаскивать разное из
функциональных языков. Было бы круто.

> Например, в WinAPI нет функции копирования директории.

А разве SHFileOperation не умеет копировать директории??

Re: Reply to your post...

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

Надо-то что-то предельно короткое и простое на такую распространённую
операцию. Типа DirСopy(from, to);

(Удалённый комментарий)
(Удалённый комментарий)
(Удалённый комментарий)
(Удалённый комментарий)
(Удалённый комментарий)
разные задачи - разные языки
было интересно взглянуть на сравнение C# vs Java ;)

Re: Reply to your post...

> разные задачи - разные языки было интересно взглянуть на сравнение
> C# vs Java ;)

Задачи пересекаются процентов на восемьдесят. Далеко не все пишут на
С++ драйвера и прочие низкоуровневые вещи.

А C# я не знаю, поэтому сравнивать не могу.

Отличная статья получилась :) Респект
Единственный но огромный минус java - это трудности "вхождения в язык". Вернее даже не в язык (не в синтаксис языка), а в саму среду виртуальной машины.
Все эти jme, jfx, jde, jdk, jee и прочее - очень запутывают сначало, не один литр водки нужен чтобы понять что к чему.

Re: Reply to your post...

Это, кстати, не особо сложно на поверку. Про большинство этих вещей на
первом этапе можно не знать вообще (я, например, про некоторые не знаю
до сих пор), но успешно и хорошо писать почти все необходимые
программы. В С++ в ряде аспектов входить гораздо тяжелее. Один только
менеджмент памяти и строки чего стоят. А когда дело доходит до потоков
и виртуального наследования - вообще тихий ужас. В Java всё это
гораздо нагляднее и на первом этапе изучить надо всего пару вещей -
установку JDK и способ компиляции/запуска. Первое вообще крайне
незамысловато (по сравнению с установкой VS, например), а второе
требует прочтения пары-тройки абзацев.

А кто-нибудь как-нибудь сравнит всё это с Delphi 7, он же [Object] Pascal в версии Borland Builder?

Ибо читаю про Java, и похоже, что все те плюсы у него уже есть. Ну и изящное begin-end вместо бессловесных скобок.

Что, и сборка мусора, вернее, автоматическое управление памятью, есть?

(Удалённый комментарий)
(Удалённый комментарий)
(Удалённый комментарий)
(Удалённый комментарий)
(Удалённый комментарий)
(Удалённый комментарий)
Наброс на 1000 камментов? =)

"Одним из принципов, определяющих направление эволюции С++, гласил, что компилятор не следует упрощать, если это создает неудобства для пользователя" (с) James Coplien, "Advanced C++ Programming. Styles and Idioms".

Так что наговариваете Вы на С++, ой, наговариваете!

Ну а если серьезно, то не далее чем месяца три назад производственная необходимость заставила вернуться на С++ с Java. Это какой-то кошмар. Я себя не на велосипеде почувствовал, а на одноколесном велосипеде. Кругом засада, враги и сатанинский смех Страуструпа.

Справдливости для отмечу. Возврат состоялся в связи с вторжением в геймдев. Писать игру, претендующую на достойные FPS, на Java я бы не решился.

Ну и давний прикол в тему:
http://blacklion.livejournal.com/337330.html

А про JME знакомый, вообще, страшные вещи рассказывал. =)

Опять же, после недавнего упсешно сданного проекта на Eclipse RCP, я не представляю как, вообще, иначе можно писать бизнес-приложения большой, географически разбросанной командой.

Re: Reply to your post...

> Наброс на 1000 камментов? =)

Пока работает. День не отвечал, а столько всего сюда написали...

> "Одним из принципов, определяющих направление эволюции С++, гласил,
> что компилятор не следует упрощать, если это создает неудобства для
> пользователя" (с) James Coplien, "Advanced C++ Programming. Styles
> and Idioms".

Принцип хороший, но плохо то, что по концепции С++ - застывший язык.
Он не будет развиваться и все недочёты останутся в нём навсегда. А с
первого раза ведь крайне тяжело всё угадать правильно.

> Справдливости для отмечу. Возврат состоялся в связи с вторжением в
> геймдев. Писать игру, претендующую на достойные FPS, на Java я бы не
> решился.

Тут тонкость. 3d-шутер или автосимулятор на Java написать нереально -
из-за производительности. А вот походовую стратегию - вполне можно.
Или квест. Или RPG. То есть, всё, что не требует адского напряжения
процессора.

(Удалённый комментарий)
C++ славится тысячами библиотек к нему (а также и к его предшественнику).

А как будет работать функция DirCopy в кроссплатформенной программе под Windows и Linux?

Сравнение не корректное. Сравнивать с Java можно только C#.

А вообще все эти языки — Java, C#, C++ — дети C.


Re: Reply to your post...

> А как будет работать функция DirCopy в кроссплатформенной программе под
> Windows и Linux? Сравнение не корректное. Сравнивать с Java можно только C#.

Забавно. Оттого что вдобавок к маразмам и ограниченностям языка С++, он ещё и не мультиплатформенный, то сравнивать нельзя?

> А вообще все эти языки — Java, C#, C++ — дети C.

А по мнению тех, кто знает языки, Java (и C# её клон) по-духу больше на Дельфи похожи. Не зря Гейтс изобретателя Дельфей на разработку Дот Нета пригласил.

(Удалённый комментарий)
Стандартный аргумент наЦистов: "С++ -- самый лучший язык, потому что самый распространённый. Не нравится -- напишите свой. Вам никто не запрещает."
:) Вобщем, либерализм в действии. Да, и переусложнение -- двигатель прогресса, как я прошлый раз писал. Без него "все бы жили в пещерах."


Мне на возмущение по поводу мусорности английского языка выдали: "
Order is for idiots. A genius can handle chaos!" (c)

То есть если вы против бесполезной растраты ресурсов (материальных, человеческих) -- вы лох. Коммунисты лохи. Остроумным людям нравятся изъяны, копание в дерьме. И главное -- нагородить кучу по-больше.

В оправдание С скажу, что там арифметика чуть по-удобнее, чем в яве, из-за ниличия беззнаковых типов. Я в яве сотни раз использовал битовую арифметику и всё равно без примера не вспомню как беззначный byte получать приведением к int-у с одновременным & 0xFF. Но самое страшное наследие ассемблера -- отсутствие модульности в С++. Безрассудным текстовым инклудом всё сваливается в одну кучу, которая после чудовищно продолжительной компиляции, нагородит вам кучу каких-то файлов и выдаст ошибку в месте, которое до инклуда компилировалось. То есть главный принцип дизайна больших систем -- "разделяй и влавствуй" (модульность)-- не обеспечивается! Приходится в голове держать название всех функций проекта, чтоб конфликтов избежать. И долго вы будете искать ошибку, возникшую на этапе линковки. Там такие прогрессивные имена вашим функциям даются. Быстрое появление средств рефакторинга для явы и отсутствие таковых для С++ (до последнего момента VC++ не мог отыскать объявления функции/переменной, работая как текстовый редактор!) доказывает нечитабельность кода на машинном уровне.

Re: Reply to your post...

> В оправдание С скажу, что там арифметика чуть по-удобнее, чем в яве,
> из-за ниличия беззнаковых типов.

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

> Я в яве сотни раз использовал битовую арифметику и всё равно без
> примера не вспомню как беззначный byte получать приведением к int-у
> с одновременным & 0xFF.

Это потому, что лучше спецконтейнер использовать.


> Но самое страшное наследие ассемблера -- отсутствие модульности в
> С++. Безрассудным текстовым инклудом всё сваливается в одну кучу,
> которая после чудовищно продолжительной компиляции, нагородит вам
> кучу каких-то файлов и выдаст ошибку в месте, которое до инклуда
> компилировалось.

Это да, но в С++ есть вещь и пострашнее. Если функцию объявить и
описать в cpp-файле, а в другом файле описать другую функцию, но с той
же сигнатурой, то в обеих файлах линкер будет использовать одну и ту
же функцию, которую выберет практически произвольно. При этом не будет
выдано не только ошибок, но и даже предупреждений.

> То есть главный принцип дизайна больших систем -- "разделяй и
> влавствуй" (модульность)-- не обеспечивается! Приходится в голове
> держать название всех функций проекта, чтоб конфликтов избежать.

namespace рулит. Но в С++ он не принудительный, что сильно портит
дело.

> И долго вы будете искать ошибку, возникшую на этапе линковки. Там
> такие прогрессивные имена вашим функциям даются. Быстрое появление
> средств рефакторинга для явы и отсутствие таковых для С++ (до
> последнего момента VC++ не мог отыскать объявления
> функции/переменной, работая как текстовый редактор!) доказывает
> нечитабельность кода на машинном уровне.

И это тоже.

Не, ну С++ с Java сравнивать — это как «семёрку» с новым «фиатом». Любому ясно, что «фиат» лучше, только дороже (эквивалентный алгоритм на С++ всё-таки быстрей, от этого никуда не деться) и в собственном гараже его не отремонтируешь (на Java в глубокие системные дебри не залезть никак).
Вот, говорят, придумал какой-то дядька язык D — тот же С++, только без недостатков. Со строками, сборщиком мусора, модулями нормальными. Не смотрели?
А с вижуал бейсиком та же проблема, что и с С++ — многолетнее наслаивание функциональности. Когда его на .NET переводили, радикально кучу старого мусора отрезали, так многомиллионная армия программистов (не забываем, что это один из самых популярных языков в мире) такой визг подняла, что пришлось часть мусора обратно засунуть. И ведь всё равно совместимость сломали между версиями, нет бы до конца дело довести...

Re: Reply to your post...

> Не, ну С++ с Java сравнивать — это как «семёрку» с
> новым «фиатом».

Да не, мне непонятно, зачем куча народа так упорно использует С++ в
тех случаях, когда на Java быстрее, надёжнее, проще, расширяемее,
короче и переносимее. Это вроде как религия что ли?

> Любому ясно, что «фиат» лучше, только дороже
> (эквивалентный алгоритм на С++ всё-таки быстрей, от этого никуда не
> деться)

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

> и в собственном гараже его не отремонтируешь (на Java в глубокие
> системные дебри не залезть никак).

Это понятно. Драйвер, конечно, не может работать через Java-машину.
Тут С++ в бесспорных лидерах. Но хорошо бы копнуть в сторону
компиляции Java-кода в машинный, а не в битовый. Такие системы уже
появляются, но как-то не активно.

> Вот, говорят, придумал какой-то дядька язык D — тот же С++,
> только без недостатков. Со строками, сборщиком мусора, модулями
> нормальными. Не смотрели?

Слышал, но не видел.

> А с вижуал бейсиком та же проблема, что и с С++ — многолетнее
> наслаивание функциональности.

Основная проблема Бейсика в том, что он уродский изначально. И это уже
не поправить без полной переработки.

(Удалённый комментарий)
..хехехе. Наброс на 1000 комментов про Цплусплус уже был в ЖЖ, и гораздо более энергичный чем у вас:
C++, Frequently Questioned Answers:
http://yosefk.com/c++fqa/
Аффтар выступил в ЖЖ и имел огромный успех:
http://community.livejournal.com/ru_programming/855147.html

> ..хехехе. Наброс на 1000 комментов про Цплусплус уже был в ЖЖ, и
> гораздо более энергичный чем у вас: C++,


У меня не наброс, у меня скрытая реклама Java. :)

Н-да, такого тщательного перемешивания мух с котлетами я давненько не видел :] Некоторые избранные моменты:

Например, в WinAPI нет функции копирования директории.

А при чем тут вообще C/C++/любой другой язык? Это особенности API конкретной ОС.

Нет функции для получения списка файлов, вместо этого есть какой-то недоитератор.

Конечно. Потому что памяти для списка может и не быть. А вообще эта претензия неуловимо напоминает о индусах, строящих агромадное DOM-представление ради выдергивания пары значений из XML'ника :]

разработчики С решили вдруг, что строки вполне можно встроить в виде char*.

С — это portable assembler. Поэтому такое представление «строк» (кавычки неслучайны) для него наиболее естественно и очевидно программисту.

Второй мощный шаг – это непредоставление способа просто и наглядно определить длину массива в штуках элементов. Можно, конечно, предположить, что таким образом экономилось место в памяти, но блин, всё равно длина массива в ней хранится, просто нет способа быстро и просто её узнать.

Где она хранится?! Во внутренних структурах аллокатора? Нет, и там не она, а какие-то внутренние данные аллокатора в каком-то его внутреннем формате. А в случае статического массива — где это она у нас хранится? Да уж, кто не бодет RTFM, тому суждено LMD...

Массив — это последовательно расположенные элементы одинаковой длины. Все. array [i] — обращение к i-тому элементу по базе array, то же самое, что *(array + i). Кстати, если у нас есть array2 = array + 1488 — где его длина должна храниться? А ведь он тоже полноценный массив ;]

Информация к размышлению:
typedef void (*interrupt_handler_t) (void);
interrupt_handler_t *interrupt_handler = (interrupt_handler_t *) где-там-эта-таблица-лежит;
...
interrupt_handler [0x15] = my_great_int15h_handler;


Или, допустим, регистры какой-то железки у нас отображены на память. Ну и т.п. «Массив с длиной» тут не в тему совершенно — а C нужен именно для этого.

Поскольку, без длины с массивом всё равно сделать почти ничего нельзя.

Угу. То-то семейство printf ну ваще не работает ;]

Справедливости ради, надо отметить, что есть функция с более очевидным названием strtod. Но ни та, ни другая не работают с std::string, то есть, опять же нужна конверсия через c_str().

Удивительно, правда? Как это функции из библиотеки C не умеют работать со структурами совсем другого языка? Непорядокъ! :]

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

ROTFL. Ну посмотрите хотя бы в свой WinAPI! В хедеры, ага. Обнаружьте, что какая-нибудь CreateWindowEx в зависимости от определений препроцессора реально может оказаться CreateWindowExA и т.п. Вот для таких тонкостей и нужен препроцессор с хедерами.

Стандартные шаманские строки, которые всех так сильно задолбали.

Меня не задолбали, хотя работаю в embedded и с C имею дело довольно часто. Что я делаю не так? Наверное, просто объяснил емаксу, что при создании нового хедера нужно в него вставлять соответствующие строчки. Дело, как всегда, не в бобине :]

Которые содержатся в каждом хэдере, поскольку далеко не все знают, что можно написать не менее шаманское #pragma once.

Да не поэтому, а потому, что нормальный программист десять раз подумает, прежде чем использовать vendor-specific extension вместо стандартной конструкции.

Но даже с прагмой вопрос остаётся открытым: а какого хрена это одноразовое включение не встроено сразу в язык?

А такого, что этот способ использования хедеров — не единственный, хоть и самый распространенный.


Короче, Вы просто не знаете C.

P.S. Но C++ — да, дрянь сказочная. Тут Вы правы.


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

(Удалённый комментарий)
(Удалённый комментарий)
Хедеры в С из-за того что язык компилирумый. Отсутствие функции копирования директорий - кроссплатформенность. С же не требует устанавливать JRE на каждую машину где код будет выполняться.

С я не защищаю, но претензии не по делу.

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

А Джава потому такая и есть что стоит на плечах гигантов, С и С++, не ругать их надо, а благодарить, что люди себе шишки набили.

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

Re: Reply to your post...

> Хедеры в С из-за того что язык компилирумый.

А паскаль-то, паскаль, неужели интерпретируемый? А сам Java? Неужели
тоже?

> Отсутствие функции копирования директорий - кроссплатформенность.

Это давно уже придумали: в стандартной библиотеке объявляется функция,
которую на каждой платформе соответствующим образом реализуют. Скажем
так, менеджмент памяти тоже ведь от платформы зависит, что не мешает
нам активно использовать malloc и new.

Для справки: стандартная в Java оконная библиотека Swing очевидно не
может быть реализована для всех платформ сразу. Тем не менее, она
стандартная и все команды едины для всех платформ. Хотя реализации,
конечно, разные.

> С я не защищаю, но претензии не по делу.

Претензия как раз по делу. Кроссплатформенность не повод для отказа от
всего, что зависит от платформы. Стандартный вывод, в частности, от
неё зависит. С чего он вдруг есть в С++?

> С++ - к сожалению было решено сделать совместимым с С. Написали бы
> новый язык не заморачиваясь с backward compatibility - получилась бы
> Джава.

Точно.

> А Джава потому такая и есть что стоит на плечах гигантов, С и С++,
> не ругать их надо, а благодарить, что люди себе шишки набили.

Опять же, совершенно точно. Поэтому я не написал "С++ - изначальный и
беспросветный отстой", а написал, что он в ряде областей устарел и на
фоне Java неудобен.

> С Джавой проблема в том что она слишком тяжелая. Для серверных
> приложений еще кое-как работает, а для клиентских - увольте.

И для клиентских нормально работает. Единственный минус - требование
Java-машины.

> Сборщик мусора вещь тоже о двух концах, особенно когда высокие
> требования к времени отклика приложения.

Это легко решается. В Java можно вызвать принудительную сборку. Хотя
это обычно и не надо.

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

Избавляет от 99% ошибок. Побить память вообще невозможно, а её утечки
возникают в крайне редких по сравнению с С++ случаях.

Ну, холиворить так холиворить...

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

Ну, а если кратко, то все просто: не нравиццо - не ешь! Нравиццо Жава? Флаг в руки и барабан на шею - вперед к светлому будущему. Нравиццо Си++? Флаг в руки и барабан на шею - вперед к светлому будущему.

Лично меня жава бесит. Но это лично я такой, знаю людей с ровно противоположенной позицией. Грубо говоря, на плюсах черта лысого можно сделать, а на жаве только тех чертей, которые кто-то уже делал. Вот она в чем разница. Если у меня задача быстро написать "обычного черта" - жава или дот нет то что надо, а вот если "необычного", то плюсы обычно рулят.

Кстати, коллектор мусора плюс только для ленивых програмеров - как только встает вопрос о времени отклика системы (гарантированного!!!) так тут же жава и дот нет идут на ЙУХ. Тогда как в плюсах уже давно можно юзать смартпоинтеры и прочие блага современного мира.

Re: Ну, холиворить так холиворить...

Кстати, коллектор мусора плюс только для ленивых програмеров

Нет, это незаменимый механизм для действительно сложных задач.

как только встает вопрос о времени отклика системы (гарантированного!!!) так тут же жава и дот нет идут на ЙУХ.

Тут всё идёт туда, кроме С.

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

Смартпоинтер - это костыль, для тех мест, где auto_ptr не работает.

(Удалённый комментарий)
Не дочитал. Обычные стоны жабера. А Ц вечен :)

Такой ответ бессмысленен и деструктивен.