Dlaczego język powinien preferować wcięcia zamiast wyraźnych znaczników bloków?

11

Uczę się Haskell i szukałem narzędzia do automatycznego wcięcia. Nie wyglądałem dużo i nauczyłem się, że w Haskell (jak w Pythonie) wcięcie oznacza blok. W rezultacie zgaduję, że niemożliwe jest stworzenie narzędzia do automatycznego formatowania, tak silnego jak w innych językach z rodziny C, które używają wyraźnych znaczników, takich jak {} (nawiasy klamrowe) lub begin endsłowa kluczowe.

Nie przeszkadza mi język wymuszający wcięcie ze względu na czytelność, ale nie rozumiem korzyści wynikających zarówno z wymuszania wcięcia, jak i posiadania wyraźnego znacznika, aby zautomatyzowane narzędzia mogły zrozumieć, co należy do którego bloku.

Jeśli preferowane jest wcięcie oznaczające blok, aby kod wyglądał lepiej, to nadal nie rozumiem korzyści. Biorąc pod uwagę, że tabulatory i spacje są różnie reprezentowane w różnych edytorach i różnych czcionkach (na przykład czcionki mono-spacje wyglądają na bardziej uporządkowane), nie można oczekiwać, że programiści zaprezentują kod poprawnie. Narzędzie, które może uwzględnić bieżący edytor tekstu, byłoby bardziej odpowiednie do prawidłowego sformatowania kodu.

Dlaczego projektant języka miałby wybierać wcięcia zamiast wyraźnych znaczników bloków?

Przywróć Monikę
źródło
8
Nie odpowiedź, ale Haskell sprawia spacje czułość dużo więcej niż opcja pytona. W większości rzeczy można użyć średników, a w razie potrzeby zawijać bloki w nawiasy klamrowe. let x =1; y = 2; z = 3jest całkowicie ważne, tak jak jest do { putStrLn $ show x; putStrLn $ show y; putStrLn $ show z; }. Te nie muszą znajdować się na tej samej linii.
KChaloux,
8
„niemożliwe jest utworzenie narzędzia do automatycznego formatowania” - w rzeczywistości nie ma takiego narzędzia do automatycznego formatowania w Pythonie z powodu reguł wcięcia.
Doc Brown
13
Um, zwiększenie wcięcia jest wyraźnym znacznikiem bloku.
Karl Bielefeldt,
3
@ K.Gkinis: Najlepszym źródłem dokładnych motywacji przy podejmowaniu decyzji dotyczących projektu języka są sami projektanci języka.
Robert Harvey,
3
To pytanie nie jest w rzeczywistości subiektywne. Pytanie, dlaczego niektórzy projektanci języków wybrali określoną składnię. Można na to odpowiedzieć. Gdyby pytanie dotyczyło najlepszej składni , byłoby to subiektywne.
JacquesB,

Odpowiedzi:

13

Guido Von Rossum

Z wywiadu z Guido Van Rossumem , który można zobaczyć w pełnym tekście na books.google.com (moje wyróżnienie ):

Wybór wcięcia dla grupowania nie był nową koncepcją w Pythonie; Odziedziczyłem to po ABC , ale zdarzało się to również w starszym języku occam. Nie wiem, czy autorzy ABC wpadli na pomysł od czasu do czasu, czy wymyślili go niezależnie, czy też był wspólny przodek. Oczywiście mogłem zdecydować się nie podążać za wskazówkami ABC, tak jak robiłem to w innych obszarach (np. ABC używał wielkich liter w słowach kluczowych i nazwach procedur, pomysł, którego nie kopiowałem), ale polubiłem tę funkcję dość nieco podczas korzystania z ABC, ponieważ wydawało się, że eliminuje on pewien rodzaj bezcelowej debaty powszechnej w tym czasie wśród użytkowników C, na temat tego, gdzie umieścić nawiasy klamrowe .

Von Rossum był mocno zainspirowany ABC i chociaż nie musiał kopiować wszystkiego, użycie wcięcia zostało zachowane, ponieważ może być korzystne w unikaniu wojen religijnych.

Byłem również świadomy, że czytelny kod i tak używa dobrowolnego wcięcia w celu wskazania grupowania, i natknąłem się na subtelne błędy w kodzie, w których wcięcie nie zgadzało się z grupowaniem składniowym za pomocą nawiasów klamrowych - programista i recenzenci przyjęli, że wcięcie pasuje do grupowania i dlatego nie zauważyłem błędu. Ponownie długa sesja debugowania udzieliła cennej lekcji.

Rossum był także świadkiem błędów spowodowanych niespójnością między grupowaniem a wcięciem i najwyraźniej poleganie na wcięciach jedynie w strukturze kodu byłoby bezpieczniejsze od błędów programowych 1 .

Donald E. Knuth i Peter J. Landin

W cytowanym wywiadzie Guido wspomina pomysł Dona Knutha na użycie wcięcia. Jest to szczegółowo opisane w cytacie „Knuth Indentation Quote” , który cytuje programowanie strukturalne za pomocą instrukcji goto . Knuth odwołuje się także do następnych 700 języków programowania Petera Johna Landina (patrz sekcja Dyskusje na temat wcięć). Landin zaprojektował ISWIM, który wygląda jak pierwszy język z wcięciami zamiast bloków początkowych / końcowych. W tych dokumentach chodzi raczej o możliwość zastosowania wcięcia w programach do strukturyzacji, a nie o faktyczne argumenty przemawiające za tym.


1. Myślę, że jest to w rzeczywistości argument przemawiający za posiadaniem zarówno konstrukcji grupujących, jak i automatycznego formatowania, w celu wychwytywania i odzyskiwania po błędach programistycznych, które muszą się zdarzyć. Jeśli zepsujesz wcięcie w Pythonie, osoba debugująca Twój kod będzie musiała zgadnąć, co jest poprawne:

if (test(x)):
  foo(x)
  bar(x)

Czy barzawsze zadzwonię, czy tylko wtedy, gdy test się powiedzie?

Konstrukcje grupujące dodają poziom redundancji, który pomaga wykryć błąd podczas automatycznego wcięcia kodu. W języku C równoważny kod może być automatycznie wcięty w następujący sposób:

if (test(x))
  foo(x);
bar(x);

Jeśli chciałem barbyć na tym samym poziomie co foo, to automatyczne wcięcie oparte na strukturze kodu pozwala mi zobaczyć, że istnieje coś złego, co można naprawić, dodając nawiasy klamrowe wokół fooi bar.

W Python: Myths about Indentation istnieje podobno zły przykład z C:

/*  Warning:  bogus C code!  */

if (some condition)
        if (another condition)
                do_something(fancy);
else
        this_sucks(badluck);

Tak samo jak powyżej, w Emacsie podświetlam cały blok / funkcję, naciskam Tab, a następnie cały kod jest ponownie dodawany. Rozbieżność między ludzkimi wcięciami a strukturą kodu mówi mi, że coś jest nie tak (to i poprzedni komentarz!).

Poza tym, kod pośredni, w którym wcięcie jest wyłączone w C, po prostu nie przechodzi przez gałąź master, wszystkie sprawdzenia stylu sprawiłyby, że GCC / Jenkins krzyczałby na mnie. Niedawno miałem problem podobny do opisanego powyżej w Pythonie, ze stwierdzeniem wyłączonym przez jeden poziom wcięcia. Czasami mam kod w C, który wykracza poza nawias zamykający, ale potem wciskam Tab i kod wcina się „niepoprawnie”: to kolejna szansa na zobaczenie błędu.

rdzeń rdzeniowy
źródło
3
„Aby uniknąć wojen religijnych ...” Jestem zaskoczony, że prawdziwy powód jest tak trywialny.
Robert Harvey,
1
@RobertHarvey: Nacisk na tę frazę ma rdzeń, a nie van Rossum. To nie jest główny powód, aby przeczytać cytat van Rossum w kontekście.
JacquesB
@JacquesB Powiedz mi, jakiego kontekstu brakuje w cytacie, abym mógł edytować odpowiedź.
rdzeń rdzeniowy
4
Nie dostaję jednak twojego osobistego komentarza: jeśli zepsułeś wcięcie w Pythonie, to masz błąd. Jeśli spieprzysz szelki w C, masz błąd. Jeśli używasz automatycznego wcięcia, jest dokładnie takie samo w obu językach. A jeśli nie użyjesz automatycznego wcięcia, błąd można ukryć w C w sposób, który nie jest możliwy w Pythonie.
JacquesB,
2
@JacquesB, ponieważ wpisywanie nawiasu zamykającego jest czynnością, którą aktywnie wykonujesz; niewystarczające wcięcie jest czymś, o czym można zapomnieć. Oczywiście możesz zapomnieć o zamknięciu klamry we właściwym czasie, ale w końcu będziesz musiał to zrobić i mieć kolejną szansę na przemyślenie. Myślę, że python działa dobrze dla początkujących, ponieważ zmusza uwagę do wcięcia.
marstato
7

Jest to bardzo subiektywne i jest przyczyną wielu wojen z płomieniami. Jednak:

Posiadanie symboli ograniczających bloki i wcięcia narusza zasadę DRY , ponieważ wyrażasz tę samą informację na dwa różne sposoby. Istnienie zautomatyzowanych narzędzi wcięcia jest symptomem naruszenia zasad DRY DRIVE: To, że możesz automatycznie wygenerować wcięcie, pokazuje, że jest to nadmiarowa informacja, a to oznacza, że ​​wcięcie i symbole mogą zsynchronizować się, co prowadzi do mylącego kodu.

Często zadawane pytania dotyczące projektowania i historii Pythona wyraźnie to stwierdzają:

Dlaczego Python używa wcięć do grupowania instrukcji?

Guido van Rossum uważa, że ​​użycie wcięcia do grupowania jest niezwykle eleganckie i ma duży wpływ na przejrzystość przeciętnego programu w języku Python. Większość ludzi uczy się pokochać tę funkcję po chwili.

Ponieważ nie ma nawiasów początkowych / końcowych, nie może być niezgodności między grupowaniem postrzeganym przez analizator składni a czytelnikiem.

Prawdą jest, że nie można utworzyć narzędzia automatycznego wcięcia dla Pythona, ale jest to dobra rzecz: oznacza to, że nie masz w składni redundancji, których potrzebujesz do automatycznego uzgadniania.

Tabulatory i spacje są uzasadnionym problemem w Pythonie i zaleca się, aby nigdy nie łączyć tabulatorów i spacji (w celu wcięcia) w tej samej bazie kodu.

Python odziedziczył znaczące wcięcie po (obecnie przestarzałym) języku poprzednika ABC. ABC jest jednym z niewielu języków programowania, które wykorzystały testy użyteczności do kierowania projektem. Tak więc, podczas gdy dyskusje na temat składni zwykle sprowadzają się do subiektywnych opinii i osobistych preferencji, wybór znacznego wcięcia ma w rzeczywistości solidniejsze podstawy.

JacquesB
źródło
6
Rachunkowość podwójnego zapisu również narusza DRY. Redundancja jest czasem cechą.
Coredump
3
@coredump: To prawda, ale jest to celowo zaprojektowana redundancja. Większość języków programowania, w tym Python, zawiera celowo wybrane redundancje - np. passSłowo kluczowe, które można wywnioskować automatycznie, ale wymaganie jego jawności pomaga wykryć błędy. Przypadkowa redundancja posiadania zarówno symboli początkowych / końcowych (dla kompilatora), jak i wcięć (dla ludzkiego czytelnika) wydaje się powodować więcej błędów niż wyłapuje. Przynajmniej wydaje się, że jest to pogląd van Rossuma.
JacquesB,
@coredump - Teraz wiem, dlaczego nie jestem księgową.
JeffO
3
@coredump Tęsknisz też za COBOL PROCEDURE DIVISION.? Nigdy nie umiem powiedzieć, gdzie DATA DIVISIONkończą się procedury i procedury w tych nowomodnych językach.
msw
2
@coredump: „zobaczenie wcięcia jest sprzeczne z tym, co miałem na myśli, wystarczy, aby zapobiec błędom” - dokładnie.
JacquesB,
2

Projektanci języków wybierają znaczące syntaktycznie białe spacje, ponieważ wierzą (lub przynajmniej sądzą, że ich potencjalni użytkownicy wierzą), że średniki i nawiasy klamrowe powodują hałas podczas czytania kodu, szkodząc produktywności. Innym częstym powodem jest to, że zły / niespójny styl kodowania szkodzi czytelności - wymuszając wspólny schemat wcięć, język ma lepszą czytelność ponad wszystko. Ten późniejszy powód jest mniej ważny, ponieważ automatyczne formatowanie IDE jest częstsze, ale nadal może mieć zastosowanie.

Telastyn
źródło
1
Rozumiem, dlaczego należy brać pod uwagę hałas średników i nawiasów klamrowych. Ale czy nie jest mniej produktywne wpisywanie 4/8/12 razy spacji? A jeśli przegapisz jedną (ponieważ są niewidoczne), masz kłopoty.
Przywróć Monikę
5
Dlatego używasz tabulacji zamiast spacji lub IDE, który rozumie, jak przekonwertować tabulatory na bloki czterech spacji.
Robert Harvey
@ K.Gkinis: Wcięcia nie są niewidoczne. Tylko białe znaki na końcach wierszy są niewidoczne, ale nie ma to znaczenia w żadnym języku. Tylko jeśli wymieszasz tabulatory i spacje, wpakujesz się w kłopoty. Więc nie rób tego.
JacquesB,
@JacquesB: problem z widocznością / niewidocznością wcięć polega na tym, że jako człowiek często nie można odróżnić spacji od tabulatora, podczas gdy komputer może i często to robi. Tak więc, gdy wcięcie jest widoczne, sposób, w jaki komputer interpretuje wcięcie, może być inny. To jest prawdziwy problem: kiedy komputer traktuje niewidzialne postacie inaczej niż ludzie. Ludzie mierzą wcięcie jako odległość na ekranie, komputery mogą mierzyć je jako dosłowną liczbę znaków. to jest niewidzialna część.
Bryan Oakley
@BryanOakley: Tak, dlatego nie powinieneś mieszać tabulatorów i spacji w wcięciach.
JacquesB