eao197 on the Web Сайт Евгения Охотникова |
[ Главная | Проекты | Описания | Об авторе ] |
В поисках лучшего языка / Почему я ищу новый язык?
В поисках лучшего языка Почему я ищу новый язык? Что не так с C++? Что хочется найти? Прощай C++? Связано ли это с SObjectizer? Языки Тестовые программы |
Ну что можно сказать?Меня C++ вполне устраивает. Я использую его с 1992 года и практически всю свою профессиональную жизнь я был C++ программистом. Может быть поэтому у меня нет проблем с использованием C++. Но... Программы не пишут в одиночкуНа C++ хорошо писать в одиночку или с двумя-тремя коллегами, которые знают его лучше тебя. Тогда код свободен от детских ошибок новичков C++, нет утечек памяти, нет повисших указателей, практически нет ручного управления памятью, разумно используются шаблоны, исключения и STL. В общем тогда все хорошо. Однако, найти готовых C++ программистов достаточного уровня сложно. А чем больше проект тем больше их нужно. В результате на C++ программируют люди, которые изучают его прямо в процессе работы. Как следствие в коде высок процент детских ошибок, являющихся следствием недостаточного знания идиом языка. Например, ручное управление памятью и другими ресурсами вместо использования std::auto_ptr и идиомы RAII. Возврат указателей или ссылок на временные объекты из функций. Передача аргументов по значению вместо использования ссылок и т.д. Все это является следствием сложности самого языка. C++ небезопасен, именно таким он создавался, именно этим он и ценен. Но когда у человека нет времени на изучение C++, то C++ оказывается слишком опасным инструментом. Кроме того, сейчас у людей не только нет времени на изучение C++, но и нет желания. Поскольку более безопасных конкурентов у C++ предостаточно. Так зачем же кому-то учить старый C++, если есть гораздо более безопасная Java и иже с ней? Все это приводит к тому, что, по моему мнению, сейчас C++ не подходит на роль языка для командной разработки. Программы требуют инструментовВремена меняются и уже невозможно написать что-нибудь более-менее серьезное с нуля. Мир потихоньку сходит с ума -- в погоне за увеличением скорости разработки происходит невообразимое наслоение технологий. Когда две программы обмениваются данными в формате XML через HTTP протокол (да еще с подписью XML и с защитой HTTP по SSL), то объем кода в библиотеках поддержки XML/HTTP может оказаться гораздо больше, чем объем самого прикладного кода. Значимость готовых, легко доступных, хорошо документированных и поддерживаемых библиотек в таких условиях сложно переоценить. Но чем дальше технологии движутся в сторону накручивания сложности, тем меньше готовых качественных библиотек оказывается для C++. Другим классом инструментов, обеспечивающих значительную степень комфорта в использовании языка, является средства разработки, IDE (Integrated Development Environment). Я давно обхожусь без IDE, vim+bash -- это практически все, что мне нужно. Но количество подобных мне приверженцев минимализма является бесконечно малой величиной, которой можно пренебречь. Особенности языка C++ не позволяют создать для него IDE, сравнимых по удобству использования и "навороченности" с IDE для таких языков, как Java и C#. Многие пользователи IDEA и Resharper рьяно доказывают, что IDE очень серьезно увеличивает их производительность и нет повода им не верить. Раз уж кому-то для написания качественного кода необходимы всплывающие подсказки, контекстно-чувствительное автодополнение, средства автоматизированого рефакторинга и пр., то ничего не поделаешь -- это тот фактор, с которым нужно считаться. В итоге, C++ прогрывает своим конкурентам как в области библиотек, так и в области IDE. Язык оказывает самое непосредственное влияние на надежность и отказоустойчивостьВ программах остаются ошибки. Это объективная реальность данная нам в неприятных ощущениях обнаружения и устранения бесчисленного количества багов. Ошибки есть всегда. Следовательно, вопрос даже не в том, сколько невыявленных багов осталось во внедренной программе. А в том, какие последствия будут у проявившихся в процессе работы ошибках. В т.н. управляемых средах последствия от выхода за пределы массива или обращения по нулевой ссылке, во-первых, не столь катастрофичны. И, во-вторых, проявляются моментально -- в виде исключений. В С++, к сожалению, эти ошибки либо могут не проявится сразу, что усугубят их последствия, либо же проявятся так, что у программы не будет шансов продолжить свое выполнение. К сожалению, именно катастрофичность проявления ошибок в C++, очень серьезно усложняет разработку приложений 24x7 (а именно этим я занимаюсь последние годы). Многопоточный сервер падает из-за обращения по нулевому указателю в одной из десятков его нитей. Падает в самый неподходящий момент, через пару месяцев непрерывной работы, без stack trace или каких-либо иных следов, облегчающих нахождение причины проблемы. Еще хуже, если ошибка не приводит к мнгновенному краху приложения, а портит какие-нибудь внутренние структры. Из-за чего крах случается совсем в другом месте и совсем в другое время... В это же самое время рядом есть совсем другой мир, в котором индексы при доступе к массивам проверяются, обращение по нулевой ссылке приводит к возникновению обычного исключения, исключения сопровождаются подробным stack trace, сборка мусора автоматически убирает грязь после упавшего из-за ошибки фрагмента кода. Просто уже хочется пользоваться этими благами цивилизации :) Объем имеет значениеГоворят, что плотность ошибок на 1000 строк кода является величиной постоянной и не зависит от используемого языка программирования. Следовательно, чем меньше кода язык позволяет писать для решения задачи, тем меньше в нем будет ошибок. Отсюда даже возник лозунг -- code less -- и к нему хочется присоединиться. Очень большой дискомфорт после Ruby в C++ вызывает объем С++ кода. Например, пусть нужно пройтись по вектору объектов и поместить их часть в два вектора-приемника, в зависимости от удовлетворения какому-нибудь условию. На Ruby это будет выглядеть как-то так: a = [ ... ] b = [] c = [] a.each do |item| if <...проверка с использованием item...> b << item else c << item end end В C++ можно либо использовать старый добрый for: typedef std::vector< SOME_TYPE > vector_t; vector_t a; ... vector_t b; vector_t c; for( vector_t::iterator it = a.begin(), it_end = a.end(); it != it_end; ++it ) if( <...проверка с использованием *it...> ) b.push_back( *it ); else c.push_back( *it ); Либо, если привлечь функторы: typedef std::vector< SOME_TYPE > vector_t; class selector_t : public std::unary_function< const SOME_TYPE &, void > { vector_t & b_; vector_t & c_; public : selector_t( vector_t & b, vector_t & c ) : b_( b ), c_( c ) {} result_type operator()( argument_type item ) { if( <...проверка с использованием item...> ) b_.push_back( item ); else c_.push_back( item ); } }; vector_t a; ... vector_t b; vector_t c; std::for_each( a.begin(), a.end(), selector_t( b, c ) ); Нужно признаться, я предпочитаю последний вариант, даже не смотря на его многословность. Потому что в самом коде работы с a, b, c использвание std::for_each гораздо более понятно и обозримо, чем for. |
© 2007-2008 Е.А. Охотников |
К сожалению я не силен в грамматике, поэтому если вы увидели здесь какие-либо орфографические или синтаксические ошибки, то не сочтите за труд -- сообщите мне. Ваша помощь поможет мне сделать этот текст гораздо лучше. |