Dlaczego większość języków programowania nie komentuje bloków?

18

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ł.

amara
źródło
jeszcze kilka odpowiedzi: och, to ma sens =) W takim razie całkowicie piszę zagnieżdżone komentarze blokowe; chociaż mam osobny etap leksykalny, nie jest to opisany ograniczający rodzaj logiki SK.
@Vuntic: Jeśli masz osobny etap leksykalny, który używa rzeczy bardziej skomplikowanych niż wyrażenia regularne, możesz mieć problemy z wydajnością. RE są szybkie i łatwe w użyciu dzięki implementacji DFA.
David Thornley,
4
@David: ... wcale nie. To jest naprawdę bardzo szybkie.
amara
Sugerowałbym, że jeśli chcesz zezwolić na zagnieżdżanie komentarzy, zezwalasz na oznaczanie znaczników początku komentarza tokenem i wymagasz, aby jeśli znacznik początku komentarza został w ten sposób zaznaczony, jego znacznik komentarza końcowego musi być oznaczony identycznie. Umożliwiłoby to szybką identyfikację niezrównoważonych tagów początkowych / końcowych i uniknięcie możliwości błędów spowodowanych przez niewykryte niezrównoważone znaczniki.
supercat

Odpowiedzi:

6

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ą, #ifale 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.

Quuxplusone
źródło
1
Mam inne zdanie na podstawie samego faktu - nie widziałem wszystkiego (i ty też nie). Więc chociaż te złote zasady, takie jak „Nie komentuj kodu”, wyglądają ładnie, życie ma swoje własne ścieżki. W tym konkretnym przypadku robię to bardzo często jako przełącznik, kiedy testuję jakąś nową funkcję i muszę stopniowo wprowadzać jakiś kod, więc komentuję kod, potem mniej, mniej, mniej, a na koniec mam element roboczy i ja może usunąć wszystkie komentarze (ponad kod). Mój idealny język oczywiście obsługuje zagnieżdżone komentarze :-).
greenoldman,
@greenoldman: Większość języków nie ma zagnieżdżonych komentarzy, ale będą one miały rzeczywistą funkcję „usuwania bloku kodu”, która jest rzadziej używana niż funkcja „zostaw komentarz”. C #if DEADjest 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.
Quuxplusone
11

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).

Logika SK
źródło
3
W dzisiejszych czasach nie zgadzałbym się z „większością”. Z pewnością jest to tradycyjny sposób, ale wiem, że w przypadku C EDG łączy preprocesor, leksykację i parsowanie, i podejrzewam, że robią to zarówno GCC, jak i Microsoft. Zaletą jest to, że pozwala je wdrażać osobno, jeśli zajdzie taka potrzeba.
Andrew Aylett,
Clang też robi to samo. Ale wciąż jest to tylko niewielka część istniejących kompilatorów popularnych języków.
SK-logic
@Neil Butterworth, spójrz na mcs, javac, gcc (tak, to poprawia lexer, ale nadal jest to dedykowane hasło leksykalne), clang (tak samo jak gcc), dmd, fpc i wiele, wiele innych.
SK-logic
Nikt nie używa wyrażeń regularnych w leksykach dla żadnego niebanalnego kompilatora.
Nuoji,
@Nuoji - dla nietrywialnych - na pewno. Ale ci, którzy polegają na elastyczności i podobnych narzędziach, robią to.
SK-logic
7

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ę.

Mike Dunlavey
źródło
1
//komentarze są również w stylu C99.
JAB
Alternatywnie, język może określać początek komentarza /*$token, gdzie identifierjest 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.
supercat
5

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.

Rugxulo
źródło
4
Do czego dodaję: Haskell, Frege
Ingo
Obsługiwany również przez Scalę.
Matt R
4

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.

Ingo
źródło
3

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.

alexrs
źródło
1
+1 za „łatwiej dodać funkcję niż ją usunąć”.
R ..
3
po zablokowaniu komentarzy zagnieżdżonych nie można na nie pozwolić, ponieważ takie komentarze /*/**/
zostaną złamane
2

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.

hammar
źródło
3
To nie jest „smak”. Słowo „regularne” w wyrażeniu regularnym z natury wyklucza rekurencję.
R ..
3
@R: Oczywiście w matematyce. Ale w programowaniu mamy rzeczy, które nazywamy wyrażeniami regularnymi, które obsługują rekurencję.
amara
Pytanie brzmi: czy to w ogóle problem? Większość języków ma już do czynienia z nawiasami zagnieżdżonymi. Aby wymienić niektóre: Lisp, C, Java, Python, Ruby, Perl.
Thomas Eding,
Zagnieżdżone nawiasy są w porządku, ponieważ elementy w nawiasach są takie same jak elementy na zewnątrz: normalne tokeny. W komentarzach nie masz tokenów, po prostu masz tekst. Musisz mieć możliwość dopasowania początkowego i końcowego tokenu komentarza, aby wiedzieć, czy „int” jest typem, czy tylko słowem w komentarzu. (Zwłaszcza jeśli wyeliminujesz komentarze w
leksykonie
2
@ThePopMachine: Jestem pewien tego, co powiedziałem, że regularny ma zdefiniowane znaczenie formalne, a nie znaczenie, którego używasz, i że dla tego znaczenia wybrano „regularne” w „wyrażeniu regularnym”. Bycie nierekurencyjnym jest jednym z jej definicji.
R ..
-1

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.

Neil Butterworth
źródło
-1

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.

Gus
źródło
3
-1: nieprawda. Rozsądne parsery tak nie działają.
amara