Jakie są przykłady niespójności i niekompletności w Unix / C?

20

W słynnym eseju Richarda Gabriela The Rise of Worse is Better kontrastuje karykaturalne wersje filozofii projektowych MIT / Stanford (Lisp) i New Jersey (C / Unix) wzdłuż osi prostoty, poprawności, spójności i kompletności. Podaje przykład „problemu utraty komputera” ( omówionego gdzie indziej przez Josha Habermana ), aby argumentować, że Unix przedkłada prostotę wdrożenia nad prostotę interfejsu.

Innym przykładem, jaki wymyśliłem, są różne podejścia do liczb. Lisp może reprezentować dowolnie duże liczby (do wielkości pamięci), podczas gdy C ogranicza liczby do stałej liczby bitów (zwykle 32-64). Myślę, że to ilustruje oś poprawności.

Jakie są przykłady spójności i kompletności? Oto wszystkie opisy Gabriela (które, jak przyznaje, są karykaturami):

Podejście MIT / Stanford

  • Prostota - projekt musi być prosty, zarówno pod względem implementacji, jak i interfejsu. Ważniejsze jest, aby interfejs był prosty niż implementacja.
  • Prawidłowość - projekt musi być poprawny we wszystkich możliwych do zaobserwowania aspektach. Niepoprawność jest po prostu niedozwolona.
  • Spójność - projekt nie może być niespójny. Projekt może być nieco mniej prosty i mniej kompletny, aby uniknąć niespójności. Spójność jest równie ważna jak poprawność.
  • Kompletność - projekt musi obejmować tyle ważnych sytuacji, ile jest praktycznych. Wszystkie uzasadnione spodziewane przypadki muszą zostać uwzględnione. Prostota nie może nadmiernie zmniejszać kompletności.

Podejście New Jersey

  • Prostota - projekt musi być prosty, zarówno pod względem implementacji, jak i interfejsu. Ważniejsze jest, aby implementacja była prosta niż interfejs. Prostota jest najważniejszym czynnikiem przy projektowaniu.
  • Prawidłowość - projekt musi być poprawny we wszystkich możliwych do zaobserwowania aspektach. Nieco lepiej jest być prostszym niż poprawnym.
  • Spójność - konstrukcja nie może być nadmiernie niespójna. W niektórych przypadkach spójność można poświęcić dla uproszczenia, ale lepiej jest porzucić te części projektu, które dotyczą mniej powszechnych okoliczności, niż wprowadzić złożoność implementacyjną lub niespójność.
  • Kompletność - projekt musi obejmować tyle ważnych sytuacji, ile jest praktycznych. Należy uwzględnić wszystkie uzasadnione spodziewane przypadki. Kompletność można poświęcić na rzecz jakiejkolwiek innej jakości. W rzeczywistości należy poświęcić kompletność za każdym razem, gdy zagrożona jest prostota implementacji. Aby zachować kompletność, można zachować konsekwencję, jeśli zachowana zostanie prostota; szczególnie bezwartościowa jest spójność interfejsu.

Pamiętaj, że nie pytam, czy Gabriel ma rację (co jest pytaniem nieodpowiednim dla StackExchange), ale o przykłady tego, do czego mógł się odnosić.

Ellen Spertus
źródło
6
Jeśli jesteś ciekawy, nie jest to zadanie domowe. Jestem nauczycielem :-) Po zastanowieniu, może to czyni moją pracę domową.
Ellen Spertus
4
Trudno mi zrozumieć, dlaczego to pytanie nie dotyczy Uniksa i Linuksa (a może inżynierii oprogramowania ?). Czy możesz wyjaśnić, w jaki sposób potrzebujesz perspektywy CS w tej sprawie? Wyjaśnij również, czy chcesz pozytywne czy negatywne przykłady.
Raphael
Czy to pytanie nie jest bardziej odpowiednie na programmers.stackexchange.com ?
Basile Starynkevitch,
Wysłałem to do CS, ponieważ uważam projektowanie języka za jedną z podstawowych głębokich dziedzin informatyki, obejmującą obliczalność, złożoność, architekturę, użyteczność itp. Mógłbym opublikować to w Unix / Linux, chociaż szukałem szerszego widok. Jeśli chodzi o programistów, ludzie prawie zawsze są mi wrogo nastawieni, kiedy tam publikuję, nawet jeśli myślę, że jestem na dany temat, więc trzymam się z daleka.
Ellen Spertus,

Odpowiedzi:

15

Tytuł pytania sugeruje, że niektóre podstawowe niespójności interfejsu użytkownika mogą Cię zainteresować:

Polecenia uniksowe nie stosują żadnej określonej składni do określania opcji i flag. Na przykład większość poleceń używa pojedynczych liter poprzedzonych przez „-” jako flagę cat -n some_file, ale wyjątki są podobne tar tf some_file.tari dd in=some_file out=some_other_file count=2występują w powszechnie używanych poleceniach.

Unix, jego potomkowie i krewni mają wiele nieco różnych składni wyrażeń regularnych. Powłoki używają „*”, gdy inne programy (grep, egrep, vi) używają „. *”. egrep ma „+” i „|” jako operatorzy grep nie.

Podstawowy interfejs wywołania systemowego „wszystko jest plikiem” może być postrzegany jako niekompletny: odczyt / zapis / wyszukiwanie / zamknięcie nie pasuje do każdego urządzenia we / wy. Niezwykle potrzebne wyjątki łączą się w połączenia „ioctl”, ale urządzenia takie jak karty dźwiękowe nawet nie pasują tak dobrze.

Bruce Ediger
źródło
Niezła odpowiedź. Kiedy zobaczyłem tytuł, od razu pomyślałem „ioctl” (i fcntl), ale teraz nie muszę wpisywać odpowiedzi.
Louis,
1
wzorce globu nie są wyrażeniami regularnymi
jk.
8

Konsystencja

Lisp ma bardzo spójną składnię, wszystkie rozszerzenia językowe można osadzać naturalnie za pomocą makr i tym podobne. Z drugiej strony C ma raczej składnię kodu, co pozwala na skorzystanie z niektórych „skrótów”, więc w niektórych przypadkach kod C wygląda na prostszy.

Kompletność

W Lisp, jeśli nie masz konkretnej funkcji językowej, której potrzebujesz, możesz ją zaimplementować samodzielnie za pomocą makr. C też ma preprocesor, ale jest raczej kłopotliwy.

Daniil
źródło
8

Ciągi C nie mogą zawierać znaku 0, a jego funkcje biblioteczne są nieodpowiednie do obsługi danych binarnych.

Nazwy plików w systemach uniksowych nie mogą zawierać znaku 0 ani znaku 47 (ukośnik).

W oryginalnej implementacji Uniksa nazwy plików były ograniczone do 14 znaków. Późniejsze wersje złagodziły to ograniczenie; nie wyeliminowali tego.

Dodano : E2BIGwarunek błędu systemu, gdy ktoś próbował execz listą argumentów, która zawierała zbyt wiele argumentów lub zajmowała zbyt dużo pamięci lub środowisko było zbyt duże.

Unix jest znany z tego rodzaju arbitralnych ograniczeń. Do czasu pojawienia się Perla w 1987 r. Obsługa dużych zestawów danych lub zestawów danych z długimi rekordami lub danymi binarnymi była wyjątkowo niewiarygodna.

Mark Dominus
źródło
Niedozwolenie /nie jest arbitralne, konieczne jest (?) Rozwiązanie niejasności, tak jak /separator ścieżki. Właśnie utworzyłem plik 000, najwyraźniej że w czasach współczesnego GNU / Linuksa nie ma określonych ograniczeń.
Raphael
Nie chciałem powiedzieć, że zakaz /był arbitralny, jedynie ograniczenia dotyczące długości linii i rozmiaru pliku były arbitralne. Chodzi jednak o to, że inny projekt mógł zawierać nazwy plików zawierające ukośniki, ale projektanci Unixa nie uważaj to za ważne.
Mark Dominus
Jestem pewien, że w tamtym czasie ograniczenia te zostały wprowadzone ze względów wydajnościowych; nierozwinięte techniki również mogą w to zagrać. Z dzisiejszego punktu widzenia wydają się wątpliwe, to na pewno. Jeśli chodzi o /mnie, jestem ciekawy: zakładając, że ścieżka powinna być zakodowana jako ciąg znaków, jak to zrobić bez zastrzeżonego znaku do rozdzielenia ścieżki?
Raphael
Nie rozumiem o co ci chodzi. Pytanie dotyczy „przykładów niespójności i niekompletności w Unix / C”; nie wspomina o wydajności.
Mark Dominus
1
@Raphael: Pozbywasz się głupich problemów z separatorem, definiując pathabstrakcyjny typ danych i wykorzystując go w swoich interfejsach zamiast ujawniania konkretnej implementacji (łańcuchy ascii zakończone zerem).
Wandering Logic
4

IIRC mój nauczyciel powiedział, że niemożność użycia char *zmiennych w switchinstrukcjach w C jest kwestią niespójności, ale dla mnie była to kwestia ogólności (kompletności). Myślę, że lepiej jest używać „spójności” tylko w swoich algorytmach lub projektowaniu oprogramowania, a nie w samym języku programowania (przynajmniej nie w językach takich jak C. być może błędny język ma problem ze spójnością), ponieważ języki programowania mają solidne standardy, które definiują dziedzinę reguł i pracuj, stosując dane wejściowe do reguł. Więc jeśli coś jest niedozwolone w języku, planowane jest, aby nie było dozwolone i nie jest niezgodne w języku, IMHO.


  1. Użyłem ogólności jako kompletności. myślę, że są tym samym. może się mylę.
  2. To nie jest odpowiedź. może sugestia lub moja opinia.
uzależniony
źródło
3

Najlepszy przykład, jaki mam, to biedny użytkownik, który miał plik o nazwie .. -ri wpisany rm *.

Niezależnie od tego, czy ta historia jest prawdziwa, czy nie, stała się klasyką hejtera uniksowego.

Zobacz The Unix-Haters Handbook , który zawiera wprowadzenie samego Dennisa Ritchiego, dla wielu takich przykładów.

Dodam ponadto, że unikanie tego typu problemów było główną siłą w projektowaniu Microsoft Power Shell.

S. Robert James
źródło
Przeczytałem esej Richarda Gabriela na końcu The Unix-Haters Handbook. :-)
Ellen Spertus
3
  • Z pewnością niezliczone znaczenia tych samych (krótkich) flag poleceń są niespójne.
  • Każdy program korzystający z wyrażeń regularnych ma dla nich własną składnię
  • Pliki konfiguracyjne dla usług mają różną składnię (można to częściowo zapomnieć, demon mailera ma niewiele wspólnego z serwerem WWW lub systemem, ale nadal)
  • Istnieją różni redaktorzy! Użytkownicy używają różnych powłok !! Dlaczego jest tak wiele środowisk pulpitu?!?

OTOH, fakt, że powłoka rozszerza globusy, a nie progam, eliminuje wiele irytujących niekonsekwencji obecnych w innych systemach. To samo dotyczy faktu, że możesz użyć tego samego polecenia do skopiowania pliku z jednego miejsca do drugiego w pliku, na dyskietce lub z dysku Zip na taśmę.

Tak więc, Unix jest niespójny. Podobnie jak inne systemy, po prostu inaczej ;-)

vonbrand
źródło
2

LISP obsługujący nieskończone liczby precyzji w porównaniu do C obsługujący tylko liczby całkowite maszynowe nie jest przykładem „poprawności” języka. Jest to prosta kwestia wynikająca z faktu, że języki miały bardzo różne cele projektowe.

Punkt C miał być językiem zbliżonym do maszyny, który mógłby zostać wykorzystany do wdrożenia systemów operacyjnych. Maszyny (głównie) nie obsługują liczb dziesiętnych o nieskończonej precyzji. Maszyny (głównie) mają liczby całkowite o stałej długości bitów.

Dave
źródło