O ile wiem, kilka osób to robi, ale żaden z nich nie jest popularny. Czy jest coś złego w zagnieżdżaniu komentarzy?
Planuję mieć blokowane komentarze w (małym) języku, nad którym pracuję, ale chciałbym wiedzieć, czy to zły pomysł.
O ile wiem, kilka osób to robi, ale żaden z nich nie jest popularny. Czy jest coś złego w zagnieżdżaniu komentarzy?
Planuję mieć blokowane komentarze w (małym) języku, nad którym pracuję, ale chciałbym wiedzieć, czy to zły pomysł.
Odpowiedzi:
Jednej rzeczy nikt jeszcze nie wspomniał, więc wspomnę o tym: chęć zagnieżdżania komentarzy często wskazuje, że programista robi to źle.
Po pierwsze, zgódźmy się, że jedyny czas, w którym „zagnieżdżanie” lub „brak zagnieżdżania” jest widoczny dla programisty, to kiedy programista pisze coś strukturalnie takiego:
do_something();
/* comment /* nested comment */ more comment */
do_something_else();
Kiedy taka rzecz pojawia się w praktyce? Z pewnością programista nie będzie pisał zagnieżdżonych komentarzy, które dosłownie wyglądają jak powyższy fragment! Nie, w praktyce, gdy zagnieżdżamy komentarze (lub chcielibyśmy je zagnieździć), to dlatego, że chcemy napisać coś takiego:
do_something(); /* do a thing */
/* [ajo] 2017-12-03 this turned out to be unnecessary
do_something_else(); /* do another thing */
*/
A to jest ZŁE. To nie jest wzór, który my (jako projektanci języków) chcemy zachęcać! Poprawny sposób pisać powyższy fragment brzmi:
do_something(); /* do a thing */
Ten „zły” kod, ten fałszywy start lub cokolwiek to było, nie należy do bazy kodów. W najlepszym wypadku należy do historii kontroli źródła. Idealnie byłoby, gdybyś nigdy nie napisał niewłaściwego kodu na początku, prawda? A jeśli niewłaściwy kod służył tam celowi, ostrzegając opiekunów, aby nie przywracali go z jakiegoś powodu, to prawdopodobnie jest to zadanie dla dobrze napisanego i celowego komentarza do kodu. Próba wyrażenia „nie rób X” przez pozostawienie starego kodu X, ale skomentowanego, nie jest najbardziej czytelnym ani skutecznym sposobem powstrzymania ludzi przed robieniem X.
Wszystko sprowadza się do prostej zasady, którą mogłeś usłyszeć wcześniej: nie komentuj kodu. (Do wyboru w tym zdaniu zamieni się na wiele z opinii w umowie ).
Zanim zapytasz: tak, języki, takie jak C, C # i C ++ już dać programiście innego narzędzia do „komentarz out” dużych bloków kodu: #if 0
. Ale to tylko szczególne zastosowanie preprocesora C, który sam w sobie jest dużym i użytecznym narzędziem. W rzeczywistości język byłby wyjątkowo trudny i wymagałby specjalnego uwzględnienia kompilacji warunkowej z obsługą, #if
ale jeszcze nie#if 0
.
Ustaliliśmy, że zagnieżdżone komentarze są istotne tylko wtedy, gdy programista komentuje kod; i ustaliliśmy (w drodze konsensusu wielu doświadczonych programistów), że komentowanie kodu jest złą rzeczą.
Aby ukończyć sylogizm, musimy zaakceptować fakt, że projektanci języków są zainteresowani promocją dobrych rzeczy i zniechęcaniem do złych rzeczy (zakładając, że wszystko inne jest równe).
W przypadku komentarzy zagnieżdżonych wszystko inne jest równe - możesz bezpiecznie zignorować nisko głosowane odpowiedzi, które twierdzą, że parsowanie zagnieżdżone /*
byłoby w jakiś sposób „trudne” dla parsera. (Zagnieżdżone /*
nie są trudniejsze niż zagnieżdżone (
, z czym już musi sobie poradzić prawie każdy parser na świecie).
Tak więc, wszystkie pozostałe były równe, należy projektant język sprawiają, że jest łatwy do komentarzy gniazdo (czyli do ustosunkowania się kod) lub trudne? Przypomnij sobie, że komentowanie kodu jest złą rzeczą.
CO BYŁO DO OKAZANIA
Notatka. Zauważ, że jeśli nie zezwolisz na zagnieżdżone komentarze, to
hello /* foo*/bar.txt */ world
jest mylącym „komentarzem” - jest równoważny z
hello bar.txt */ world
(co jest prawdopodobnie błędem składni). Ale jeśli zrobić pozwalają zagnieżdżone komentarze, a następnie
hello /* foo/*.txt */ world
jest mylącym „komentarzem” - jest równoważny z
hello
ale pozostawia komentarz otwarty aż do końca pliku (co znowu prawie na pewno jest błędem składniowym). Tak więc żaden sposób nie jest szczególnie mniej podatny na niezamierzone błędy składniowe. Jedyna różnica polega na tym, jak radzą sobie z umyślnym antypatternem skomentowanego kodu.
#if DEAD
jest kanonicznym i najlepiej zaprojektowanym przykładem. W wielu językach możesz po prostu owinąć martwy kod w odpowiednik if (DEAD)
. W wielu IDE możesz faktycznie usunąć martwy kod i polegać na Ctrl + Z i / lub kontroli wersji, aby odzyskać go, jeśli chcesz. Pozostawienie komentarza, docstring, cokolwiek, którego tekst jest wiązką martwego kodu, jest nadal najgorszą opcją dla czytelności.
Ponieważ większość implementacji używa osobnych etapów leksykalnych i parsowania, a do leksykalizacji używają zwykłych starych wyrażeń regularnych. Komentarze są traktowane jako białe spacje - tzn. Zignorowane tokeny, i dlatego powinny być rozwiązane całkowicie w przebiegu leksykalnym. Jedyną zaletą tego podejścia jest szybkość analizowania. Liczne wady obejmują poważne ograniczenia składni (np. Potrzeba utrzymania stałego, niezależnego od kontekstu zestawu słów kluczowych).
Zupełnie możliwe jest stworzenie leksemu, który poradzi sobie z zagnieżdżonymi komentarzami. Kiedy je białe znaki, gdy je widzi /*
, może zwiększać licznik głębokości i zmniejszać je, gdy widzi */
, i zatrzymywać się, gdy głębokość wynosi zero. To powiedziawszy, zrobiłem wiele parserów i nigdy nie znalazłem dobrego powodu do umieszczania komentarzy.
Jeśli komentarze mogą się zagnieżdżać, to wadą jest łatwe wyważenie ich końców, i jeśli nie masz fantazyjnego edytora, może on niewidocznie ukryć kod, który, jak zakładasz, istnieje.
Pozytywną stroną komentarzy, które się nie zagnieżdżają jest coś takiego:
/*
some code
more code
blah blah blah
/**/
gdzie możesz z łatwością komentować i usuwać kod, usuwając lub dodając pierwszy wiersz - edycja 1-wierszowa. Oczywiście, jeśli sam kod zawiera komentarz, to się zepsuje, chyba że dopuścisz również //
komentarze w stylu C ++ . Więc to właśnie robię.
//
komentarze są również w stylu C99.
/*$token
, gdzie identifier
jest dowolny token alfanumeryczny, a koniec komentarza to token$*/
. Stosunkowo łatwo byłoby włączyć tokenizatorowi kod, aby sprawdzić, czy każdy znak komentarza końcowego zawiera odpowiedni token dla pasującego bloku komentarza początkowego.
Ponieważ nikt inny o tym nie wspominał, wymienię kilka języków, które obsługują zagnieżdżone komentarze: Rexx, Modula-2, Modula-3, Oberon. Pomimo wszystkich skarg dotyczących trudności i prędkości, żaden z nich nie wydaje się mieć żadnych poważnych problemów.
Dobrym punktem do zagnieżdżania komentarzy blokowych jest to, że można łatwo komentować duże części kodu (cóż, prawie, chyba że sekwencja końcowa komentarza bloku jest stała).
Alternatywną metodą jest wstawienie wiązki linii z sekwencją początkową komentarza do linii, jeśli masz edytor, który ją obsługuje.
Haskell zagnieżdżał komentarze blokowe, ale większość ludzi nie zauważa lub narzeka. Wydaje mi się, że dzieje się tak, ponieważ ludzie, którzy nie oczekują zagnieżdżonych komentarzy, unikają ich, ponieważ byłby to błąd leksykalny w innych językach.
Obsługa zagnieżdżonych komentarzy blokowych komplikuje parser, co jest zarówno pracochłonniejsze, jak i może wydłużyć czas kompilacji. Myślę, że nie jest to bardzo potrzebna funkcja dla języka, więc lepiej jest wykorzystać czas i wysiłek na inne ulepszenia i optymalizacje.
Moim zdaniem prostota jest zawsze dobrą rzeczą w projektowaniu czegokolwiek. Pamiętaj, że łatwiej jest dodać funkcję niż ją usunąć. Gdy dopuścisz zagnieżdżone komentarze i będą dostępne programy, nie będziesz mógł ich usunąć bez naruszenia kompatybilności.
/*/**/
Jednym z prawdopodobnych powodów jest to, że analizatory zagnieżdżone muszą być obsługiwane przez analizator składni, ponieważ smak wyrażeń regularnych często używanych w leksykonach nie obsługuje rekurencji. Proste mogą zostać wyeliminowane przez leksykon jako białe spacje, dzięki czemu łatwiej je zaimplementować w ten sposób.
Kto wie? Sądzę, że ponieważ obsługa zagnieżdżonych komentarzy jest bardziej pracochłonna - trzeba by utrzymać jakiś stos i ponieważ komplikuje to gramatykę języka.
Zagnieżdżone komentarze oznaczają dodatkową pracę dla parsera. Zwykle, gdy widzisz początek komentarza, ignorujesz wszystko aż do znacznika komentarza końcowego. Aby wesprzeć zagnieżdżone komentarze, musisz również parsować tekst w komentarzach. Największym problemem jest jednak to, że programista musi uważnie zamykać wszystkie zagnieżdżone komentarze poprawnie, w przeciwnym razie doprowadzi to do błędów kompilacji. Prawidłowe wdrożenie kompilatora jest czymś, co można zrobić, ale śledzenie zagnieżdżonych komentarzy jako programisty jest dość podatne na błędy i irytujące.