Довелось заглянуть в исходники одной сишной библиотеки. Что за библиотека и зачем я туда полез -- дело десятое, к теме сегодняшнего разговора отношения не имеющее. А вот то, какой код обнаруживается в нее в потрохах, заслуживает пристального внимания. Ибо код этот является отличным образчиком тщательно написанного обычного кода на C. Подчеркну -- обычного кода. Написанного обычными разработчиками, а не гуру калибра Линуса Торвальдса. Посему выглядит обычный код на C вот так:
int ub_ctx_add_ta(struct ub_ctx* ctx, const char* ta) { char* dup = strdup(ta); if(!dup) return UB_NOMEM; lock_basic_lock(&ctx->cfglock); if(ctx->finalized) { lock_basic_unlock(&ctx->cfglock); free(dup); return UB_AFTERFINAL; } if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_list, dup)) { lock_basic_unlock(&ctx->cfglock); free(dup); return UB_NOMEM; } lock_basic_unlock(&ctx->cfglock); return UB_NOERROR; } |
Классно, не правда ли? Прилежанию автора можно только позавидовать.
А потом настучать по рукам. За то, что не использует хотя бы идиому goto cleanup. Если уж перейти на C++ ума не хватило.
Если вам кажется, что это что-то из ряда вон, то это вы еще не видели следующей функции, которая в коде идет прямо вслед за только что показанной:
int ub_ctx_add_ta_file(struct ub_ctx* ctx, const char* fname) { char* dup = strdup(fname); if(!dup) return UB_NOMEM; lock_basic_lock(&ctx->cfglock); if(ctx->finalized) { lock_basic_unlock(&ctx->cfglock); free(dup); return UB_AFTERFINAL; } if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_file_list, dup)) { lock_basic_unlock(&ctx->cfglock); free(dup); return UB_NOMEM; } lock_basic_unlock(&ctx->cfglock); return UB_NOERROR; } |
Ну как? Ничего не напоминает? Ну тогда давайте посмотрим еще одну, которая идет прям следом:
int ub_ctx_add_ta_autr(struct ub_ctx* ctx, const char* fname) { char* dup = strdup(fname); if(!dup) return UB_NOMEM; lock_basic_lock(&ctx->cfglock); if(ctx->finalized) { lock_basic_unlock(&ctx->cfglock); free(dup); return UB_AFTERFINAL; } if(!cfg_strlist_insert(&ctx->env->cfg->auto_trust_anchor_file_list, dup)) { lock_basic_unlock(&ctx->cfglock); free(dup); return UB_NOMEM; } lock_basic_unlock(&ctx->cfglock); return UB_NOERROR; } |
А следом идет еще одна такая же. С точностью до одного имени при вызове cfg_strlist_insert во втором if-е.
Лепота!
Боюсь, если теперь мне кто-нибудь всерьез начнет доказывать, что писать код на C проще, что код на C понятнее, что бинарники не пухнут за счет шаблонов, что нет непоняток с тем, какое, где и откуда может выскочить исключение... Так вот, боюсь, я не только не смогу всерьез относиться к таким словам. Мне еще будет настолько жаль потраченного на общение с такими гореспециалистами времени, что от досады могу не сдержаться.
Нет, ну блин, просто попробуйте представить себе как будет выглядеть хотя бы одна из этих функций, написання с использованием STL-я и исключений. Ведь будет что-то вроде:
void ub_ctx_add_ta(ub_ctx & ctx, std::string ta) { std::lock_guard<some_lock> lock(ctx.cfglock); if(ctx.finalized) throw some_exception(UB_AFTERFINAL); ctx.env->cfg->trust_anchor_list.insert(std::move(ta)); } |
И это все!
Ну ладно, исключений еще некоторые боятся как огня, поэтому строчат простыни кода с ручной очисткой ресурсов и if-ом на каждый чих, проявляя чудеса внимания и усидчивости. Давайте представим, как этот же код можно записать на C++ без исключений.
int ub_ctx_add_ta(ub_ctx& ctx, const char* ta) { std::unique_ptr<char, decltype(&free)> dup(strdup(ta), &free); if(!dup) return UB_NOMEM; std::lock_guard<some_lock> lock(ctx.cfglock); if(ctx.finalized) return UB_AFTERFINAL; if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_list, std::move(dup))) return UB_NOMEM; return UB_NOERROR; } |
Неужели это, блин, настолько сложнее, чем сплошная копипаста на сишечке???
Даже над уже показанным кодом можно и еще постебаться. А ведь это были самые простые и компактные примерчики. Уверяю, там есть и еще похлеще.
В общем, чего хочу сказать. На дворе, мать его, XXI век. Для дебилов, которые не сумели освоить C++, но вынуждены писать нативный код, уже есть Go. Тупой, безопасный и со специальной конструкцией defer, специально вставленный в этот убогий язык, дабы умственно отсталым не приходилось прибегать ни к копипасте, ни к goto cleanup для очистки ресурсов. Еще есть D со scope(exit). А еще год назад релиз Rust-а состоялся. Но нет. Дебилы продолжают педалить мегатонны говнокода на теплой ламповой сишечке. И еще радостно визжать о том, насколько им нравится это делать.
Комментариев нет:
Отправить комментарий