Отварящата скоба и новият ред

Върл привърженик съм на идеята, че няма значение каква е конвенцията, стига да се спазва от всички в екипа с религиозен фанатизъм. Дори веднъж, когато приготвях pull request за един проект, се усъмних, че не съм съвсем в тон със стилистиката му. Прегледах кода още веднъж, и установих, че автора никъде не е ползвал unless – вместо това навсъкъде прави if !. Никак не бях съгласен с тази идея, но това не бе моя проект и послушно заместих моя unless с неговия if ! преди да отворя PR-а. Но има една конвенция, която не ми се е налагало да следвам, и ми е трудно да си представя как бих я понесъл.

Говоря за отваряща „къдрава“ скоба на нов ред. Така и не схванах защо някой би предпочел да го прави. Но след като препрочетох K&R, мисля че разбрах откъде идва.

За щастие, това в днешно време се прави предимно в продуктите на Microsoft и някак ми се разминава да работя с така подреден код. Нито ми се струва по-информативно визуално, нито ми е по-лесно да разпознавам блоковете, нито мога да си представя някаква естетическа причина, поради която бих намерил това за „по-красиво“. С каквито и очи да гледам кода, всеки път се чудя защо трябва да се похабява по цял отделен ред.

Препрочитайки K&R, останах с впечатлението, че причината тази конвенция да се появи, е причината за повечето странни неща в софтуера – legacy.

В книгата дефинират функции така:

void print_strings(char **names, int size)
{
    int i;

    for (i = 0; i < size; i++) {
        printf("%s\n", names[i]);
    }
}

Забележете как само отварящата скоба на print_strings е на нов ред. Тази на for – и на if, while и прочее – е на същия ред. Причината за това? Промени в C стандарта.

Достолепния ANSI C стандартизира определянето на типове при параметрите на функции, при това, във вида по-горе. В по-ранните години на езика е ставало по следния начин:

void print_strings(names, size)
char **names;
int size;
{
    int i;

    for (i = 0; i < size; i++) {
        printf("%s\n", names[i]);
    }
}

Докато в днешно време ще се озорите да намерите компилатор, който изисква втория стил, едно време далеч не е било така (под „едно време“ разбирайте „преди повечето от нас да се родят“). В тази нотация е съвсем естествено скобата да е на отделен ред. Колкото и субективни да са естетическите въпроси, навярно всички ще се съгласим, че това скобата да стои след int size; би било „грозно“.

Тази времена са отдавна отминали, обаче, и сега първия стил е далеч по-приет. Всъщност, не се съмнявам втория стил да изненада немалко съвременни C програмисти. Въпреки това, тази конвенция не просто е намерила начин да оцелее, но и да се разпространи до другите конструкции, където въобще не е нужна.

Не успях да намеря друг източник на тази толкова странна според мен практика. Докато това не доказва нищо, не мога да не си мисля, че е една от страните в една от старите безполезни „религиозни войни“ (подобно на vi vs. Emacs) защитава legacy позиция. И докато бих спазвал тази конвенция, макар и с огромно неудоволствие, едва ли ще мога да се оттърся от усещането, че не режа краищата на ястието без причина.

А вие знаете ли друга, по-правдовоподобна история, за отварящата скоба на нов ред?

11 thoughts on “Отварящата скоба и новият ред

  1. Продължавам да не разбирам защо държите на ръка да форматирате кода си.

    Съжалявам, практиката ми показва, че във всеки екип в който съм бил, наличието на автоформатър при всички от екипа, който on Save се оправя с всички подобни тривиални неща, ни освобождава главите от подобни „велики“ полемики. Всичко е консистентно. Винаги. Всички са щастливи. Zero cognitive effort. End of story.

  2. Не виждам връзката между „ръчното форматиране“ на кода и конвенцията, която се спазва. Не виждам и полемика, но това е друг въпрос :)

    Също, предполагам, че пишеш на C# или Java, където положението с такива инструменти е доста приятно. В много други езици обаче, нямаш адекватни инструменти, които да форматират кода автоматично. Впрочем, Go има много хубаво решение на този въпрос – още със създаването си върви с инструменти за форматиране и съществуващия Go код е изключително консистентен.

    Но ситуацията в ред други (при това популярни) езици не е такава. И отново, това дали имаш такъв инструмент и как той подрежда са две различни неща.

  3. Кода най-визуално се възприема на блокове. Като има доза смисъл, заглавието и съдържанието да са два различни такива.

    Следния пример: https://gist.github.com/sovanesyan/8351453

    Аз съм привърженик на новия ред, и ми изглежда като най-хигиеничното и чисто нещо на света.

    That being said, ако заглавието имаше по-ярко и открояващо оцветяване може би нямаше да мисля така. Не бих се и налагал в съществуващ проект.

  4. Бъси кефа, в нашто семейство легендата е с точените кори на баницата, които винаги се замятат в края на тавата!

  5. За мен скоба на отделен ред позволява по-лесно визуално ориентиране и по-добър изглед върху кода. Също така ми изглежда по-естествено – скоба на същия ред ми изглежда все едно кодът изкуствено е сгъчкан т.е. ето така:

    int x; a = 42;

    Единственият плюс, който виждам на скоба на същия ред е, че позволява повече код да се вижда без scroll-ване. Същата логика обаче е приложима и в горния пример.

    Python се справя с този религиозен спор доста елегантно :)

  6. Дали кода изглежда сгъчкан или не е отвсякъде въпрос на навик. Ако си свикнал с едното, другото ще ти изглежда странно. Аз (почти) никога не съм ползвал тази конвенция и скобата на нов ред ми изглежда объркващо и заемащо място. Също, струва ми се, че блока няма нищо общо с конструкцията преди него. В крайна сметка:

    {
        …
    }

    е валиден начин да създадеш лексикален scope – именно това очаквам, като видя отваряща скоба на отделен ред.

  7. Серж Ованесян е прав. Наистина кода най-добре се възприема на блокове, но не виждам какъв му е проблема на варианта без нов ред за отварящата скоба. Не само, че е достатъчно ясен (тялото е отместено навътре в отделен блок), ами даже и реда със затварящата скоба на мен ми е малко излишен (може би заради Python, но това е друга тема).

    А отностно оцветяването на заглавието – това не е проблем на форматирането, а на цветовата схема която се ползва. При подходяща такава прекрасно си разбираш кое какво е.

  8. Ето моя теория по въпроса.

    В C отварящата къдрава скоба е многозначна. Тя може да означава като then в условен оператор, do в for..do или while цикъл, но така и begin във функция и процедура.

    Затварящата къдрава, скоба обаче не е – тя изпълнява ролята на end/stop на блок от код, независимо дали този блок е процедура, условен клон или цикъл.

    Традицията е begin инструкцията да се изписва на нов ред. Бих предположил, че това е заради по-голямото логическо значение на този блок от код.

    От друга страна условния и оператора за цикъл са помощни инструменти, в контекста на самостоятелен блок от процедурен код. В тях смислената част е самия оператор, който е на нов ред, а не синтаксиса, който завършва началото на оператора (then или do).

  9. За това, че начинът по който ти изглежда един код (сгъчкан, неестествен и прочие) е въпрос на навик си прав – аз минах от скоба на същия ред към скоба на нов ред преди много години и спомените ми са, че скоба на нов ред тогава ми се струваше също толкова неестествена и неприятна за четене колкото скоба на същия ред сега. Моето лично впечатление – скоба на нов ред по-отчетливо разделя визуално съдържанието на блока (действието което се изпълнява) от неговият „header“ (условието при което се изпълнява това действие). Това ми помага да се ориентирам по-добре при бързо скролване през голямо количество код. Виждал съм ‘скоба-на-същия-ред’ код в който в началото на всеки блок оставят по един празен ред, предполагам със същата цел.

  10. Кое ви изглежда по добре като пишете js ?

    (function() {
        // Handler
    })();

    или

    (function()
    {
        // Handler
    })();

Вашият коментар

Вашият имейл адрес няма да бъде публикуван. Задължителните полета са отбелязани с *