среда, 27 января 2016 г.

[prog.flame] Писать на plain old C вместо C++? А с головой у вас все нормально?

На C++ плотно и осмысленно программирую где-то с 1992-го года (до этого был еще небольшой период времени, когда я не знал, что C и C++ -- это два разных языка). За это время довелось наслушаться столько критики C++ и рекомендаций использовать вместо C++ другие языки, что мало не кажется :) В разное время назывались разные альтернативы: Common Lisp, Ada, Modula-2, Pascal и Object Pascal, Oberon, Java, Eiffel, C#, D, OCaml, Haskell, Rust и Go. И это не считая разной скриптодинамики вроде Python-ов с Perl-ами и Ruby-ями.

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

О том, что голый C для системного программирования лучше C++, говорили всегда. Не всем C++никам это нравилось, т.к. и само системное программирование сильно разное, и на C++ можно программировать очень по разному. Но тут, действительно, можно было вести предметный спор и за plain old C были и есть весьма весомые аргументы, начиная от того, что при работе поверх голого железа жирного рантайма C++ и ряда C++ных плюшек просто не будет, заканчивая наличием C-шного компилятора практически для всех платформ, чем C++ не мог похвастаться, особенно в былые годы.

Так что касательно низкоуровневого системного программирования plain old C до сих пор имеет серьезное преимущество перед C++. И лично мне бы хотелось, чтобы это преимущество только возрастало, а C++ становился бы все более и более высокоуровневым языком.

Но вот в последние лет 5 (плюс-минус год-два) доводится наблюдать картину, когда plain old C противопоставляют C++ даже в области разработки ПО промежуточного слоя и, что совсем уже маразматично, прикладного ПО. Попробую объяснить причину этого феномена исходя из своего разумения ситуации в софтостроении.

Происходит это из-за того, что мощность вычислительной техники за последние 25-30 лет выросла настолько, что софт, работающий с приемлемой для пользователя скоростью, теперь можно писать даже на тормозящей динамике вроде Python, Ruby и JavaScript. Молодежь может не помнить, но 30 лет назад C++ оказался популярнее многих безопасных языков со сборкой мусора по одной простой причине: не хватало мощности тогдашнего железа для языков вроде SmallTalk или CommonLisp. Точнее, такое железо тоже было, но доступно оно было не только лишь всем. Я, например, учился программировать сначала на БК1001 с 16Kb RAM, затем на Robotron 1715 с 64Kb RAM, затем на IBM XT 8086 с 640Kb памяти и тактовой частотой всего в несколько мегагерц. Кстати говоря, эта XT-шка оказалась первой машиной, в которой бы жесткий диск. А на 386-ю с 4Mb памяти довелось попасть в году, кажется, 1994-м.

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

Как бы то ни было, если изначально Python и Ruby использовались как продвинутые bat- или sh-файлы, а JavaScript применялся только для того, чтобы замораживать или размораживать пару кнопок на формочке в веб-страничке, то со временем стало возможно использовать эти языки для разработки нормальных, полноценных приложений. Ну а в местах, где скорости все-таки не хватает или же нужно получить доступ к какому-то системному API, используются расширения, написанные на C.

Отсюда и появляется когорта разработчиков, которые знают Python или JavaScript плюс немножко знают C. И, может быть, когда-то краем глаза видели C++. Или только слышали про C++ городские легенды о том, что если C и позволяет легко прострелить себе ногу, то уж в C++ в этом случае нога не просто простреливается, а отстреливается нахрен, вместе с яйцами и изрядным куском спинного мозга, а в образовавшуюся дыру вытекают остатки головного мозга. Причем априори понятно, что у человека, выбравшего C++ в качестве языка реализации в голове могут быть лишь остатки головного мозга, т.к. любому нормальному разработчику понятно, что брать C++ нельзя ни в коем случае. Если уж нужна скорость, то старая, добрая, можно сказать, ламповая сишечка и все.

Видимо, остатки моего головного мозга давным-давно вытекли в дыры после отстрела ног и прочих конечностей за более чем 20-летнюю работу с C++... Но понять, как можно выбирать plain old C для прикладной разработки вместо С++ в современных условиях не могу. Сам я в начале 90-х с чистого C ушел на C++ как только понял, насколько проще и безопаснее программировать на C++, не сильно проигрывая в скорости. И это был очень древний C++, в котором не было ни шаблонов, ни исключений, а результат new нужно было проверять на 0. С тех пор прошло более 20 (двадцати, Карл!) лет. Уже C++98 был намного лучше, чем C++ в 92-м. А про современный C++ и говорить не приходится.

И вот зная все это, и даже постарев и осознав, что в Интернетах больных на голову, но активно выражающих себя идиотов гораздо больше, чем где-либо, все равно не перестаю удивляться, как можно всерьез советовать использовать plain old С вместо С++. Еще раз: старый C вместо современного C++.

Если среди читателей есть приверженцы старой ламповой сишечки, то скажите, вы всерьез предпочитаете писать такой код:

#include <stdio.h>
#include <stdlib.h>

int main()
{
   const size_t N = 102400;

   unsigned int * v = (unsigned int *)malloc( N * sizeof(unsigned int) );
   if( !v )
      abort();
   forunsigned int *p = v, *e = v + N; p != e; ++p )
      *p = 1;
   unsigned int r = *v;
   forunsigned int *p = v+1, *e = v + N; p != e; ++p )
      r += *p;
   free(v);

   printf( "%u\n", r );

   return 0;
}

Вместо вот такого:

#include <vector>
#include <iostream>
#include <numeric>

int main()
{
   using namespace std;

   vector< unsigned int > v( 1024001 );
   auto r = accumulate( ++begin(v), end(v), *begin(v) );
   cout << r << endl;

   return 0;
}

Вы это серьезно?

Если да, то попробуйте в приведенном выше примере поменять тип элемента динамического массива с unsigned int на short. Где это будет сделать проще?

И это самая тривиальная задачка. Что уже говорить про более сложные ситуации. Сколько усилий вам нужно будет приложить, чтобы реализовать в C такую вещь, как "множество чисел"? А такую, как Boost.MultiIndex?

Так что творятся в мире какие-то странные вещи, недоступные моему пониманию. Когда C используется для написания ядер ОС, драйверов, встраиваемого ПО -- тут без вопросов, у C здесь есть серьезные преимущества (хотя язык вроде Rust-а тут мог бы найти себе применение). Но вот уже на уровне чуток повыше, скажем, HTTP-сервера, СУБД, MQ и т.д., не говоря уже про прикладные приложения (особенно с продвинутым GUI) говорить о каких-то преимуществах C над C++ очень сложно. Если вообще возможно.

Комментариев нет: