Jaka jest największa wada projektowa, z jaką się spotkałeś w jakimkolwiek języku programowania? [Zamknięte]


29

Wszystkie języki programowania mają swoje wady projektowe po prostu dlatego, że żaden język nie może być idealny, tak jak większość (wszystkich?) Innych rzeczy. Poza tym, który błąd projektowy w języku programowania najbardziej cię irytuje w twojej historii jako programisty?

Zauważ, że jeśli język jest „zły” tylko dlatego, że nie jest przeznaczony do konkretnej rzeczy, nie jest to wada projektowa, ale cecha projektu, więc nie wymieniaj takich irytacji języków. Jeśli język jest nieodpowiedni do tego, do czego jest przeznaczony, jest to oczywiście wada w projekcie. Rzeczy specyficzne dla realizacji i pod maską też się nie liczą.


6
Pamiętaj, że jest to konstruktywne dla projektantów języków (błędów, których należy unikać), jeśli ktoś chciałby zapytać, jak konstruktywne jest to pytanie.
Anto


1
@greyfade: Nie bardzo, chodzi tu o wady w rzeczywistym języku, wydaje się, że chodzi o rzeczy, które obniżają adopcję języka, co może obejmować złą standardową bibliotekę lub po prostu złą stronę internetową dla tego języka. Niektóre odpowiedzi wymieniają np. Złą składnię, ale to nie jest szczególna wada projektowa
Anto

8
Największa wada w jakimkolwiek języku programowania? Ludzie
Joel Etherton,

Jeśli te odpowiedzi są największe wady, to naprawdę jestem pod wrażeniem języków programowania.
Tom Hawtin - tackline

Odpowiedzi:


42

Jedną z moich dużych irytacji jest sposób, w jaki switchprzypadki w językach pochodnych C domyślnie przechodzą do następnej sprawy, jeśli zapomnisz użyć break. Rozumiem, że jest to przydatne w kodzie bardzo niskiego poziomu (np. Duff's Device ), ale zwykle jest nieodpowiednie dla kodu poziomu aplikacji i jest częstym źródłem błędów kodowania.

Pamiętam około 1995 r., Kiedy po raz pierwszy czytałem o szczegółach dotyczących Javy, kiedy doszedłem do tej części switchoświadczenia, byłem bardzo rozczarowany, że zachowali domyślne zachowanie awaryjne. To po prostu staje switchsię uwielbione gotopod innym imieniem.


3
@Christopher Mahan: switchnie musi tak działać. Na przykład instrukcja case / when Ady (odpowiednik przełącznika / case) nie ma zachowania awaryjnego.
Greg Hewgill

2
@Greg: switchpodobne instrukcje w językach niezwiązanych z C nie muszą tak działać. Ale jeśli używasz przepływ sterowania C-Style ( {... }, for (i = 0; i < N; ++i), return, etc.), język wnioskowanie oczekiwać, że ludzie będą switchpracować jak C, nadając mu Ada / Pascal / BASIC-like semantyki byłby mylić ludzi. C # wymaga breakw switchinstrukcjach z tego samego powodu, chociaż czyni go mniej podatnym na błędy, zabraniając cichego przewracania się. (Ale chciałbym, żebyś pisał fall;zamiast brzydkiego goto case.)
dan04

4
następnie nie pisz przełącznika, pisz if () else. powodem, dla którego narzekasz, jest to, co sprawia, że ​​zmiana jest lepsza: nie jest to warunek prawda / fałsz, to warunek liczbowy, a to czyni go innym. Możesz także napisać własną funkcję przełącznika.
Jokoon

9
-1 Uważam za korzyść pozwolić na upadek, nie ma innego niebezpieczeństwa niż głupota, ale zapewnia ona dodatkową funkcję.
Orbling

11
Problemem nie jest to, że switch pozwala na upadek. Chodzi o to, że większość zastosowań upadku nie jest zamierzona.
dan04

41

Nigdy tak naprawdę nie podobało mi się używanie =do zadań i ==testów równości w językach pochodnych C. Potencjalne zamieszanie i błędy są zbyt duże. I nawet nie zaczynaj mnie od ===Javascript.

Lepiej byłoby :=dla zadania i =dla testów równości. Semantyka mogłaby być dokładnie taka sama jak dzisiaj, gdzie przypisanie jest wyrażeniem, które również wytwarza wartość.


3
@Nemanja Trifunovic: Początkowo myślałem o tej sugestii, ale ma niefortunną dwuznaczność w C z mniej niż porównaniem z liczbą ujemną (tj. x<-5). Programiści C nie tolerowaliby tego rodzaju wymaganych białych znaków :)
Greg Hewgill

7
@Greg: Wolałbym, :=a ==ponieważ zbyt łatwo byłoby zapomnieć :i nie zostać powiadomionym, jak to już jest (choć cofnięte), gdy zapomnisz =dzisiejszego dnia. Jestem wdzięczny za ostrzeżenia kompilatora dotyczące tego ...
Matthieu M.

13
Na prawie wszystkich klawiaturach, których kiedykolwiek używałem, „: =” wymaga zmiany klawisza Shift podczas pisania. W tym, którego używam teraz, „:” to wielkie litery, a „=” to małe litery, a ja to odwróciłem. Piszę wiele zadań i nie potrzebuję tego rodzaju kłopotów z pisaniem.
David Thornley,

14
@David Thornley: Kod jest czytany wiele razy więcej niż jest napisany. Nie kupuję żadnych argumentów na temat „kłopotów z pisaniem”.
Greg Hewgill,

8
@Greg Hewgill: Jasne, że czytane są częściej niż napisane. Jednak problemem między czytaniem =a jego brakiem ==jest to, że są to odrębne symbole. Jest na piśmie i upewnia się, że masz właściwy.
David Thornley,

29

Wybór +w JavaScript zarówno dodawania, jak i łączenia ciągów był strasznym błędem. Ponieważ wartości są bez typu, prowadzi to do bizantyjskich reguł, które określają, czy +dodają, czy konkatenują, w zależności od dokładnej zawartości każdego argumentu.

Na początku łatwo byłoby wprowadzić zupełnie nowy operator, na przykład $do łączenia łańcuchów.


13
@Barry: Nie bardzo. +ma sens jako operator konkatenacji łańcuchów w silnie typowanym języku. Problem polega na tym, że JavaScript go używa, ale nie jest mocno wpisany.
Mason Wheeler

13
@Mason: +nie ma sensu konkatenacja, ponieważ konkatenacja zdecydowanie nie jest przemienna. Według mnie jest to nadużycie.
Matthieu M.

12
@Matthieu: Umm ... dlaczego to ma znaczenie? Łączenie nie jest przemienne (podobnie jak dodawanie), ale dodanie dwóch ciągów jest nonsensowne, więc nikt nie myśli o tym w ten sposób. Wymyślasz problem, którego nie ma.
Mason Wheeler,

4
wystarczy przełączyć się na C ++ i dodać dowolnego ezoterycznego przeciążenia do wybranego operatora
Newtopian

8
@Matthieu: Komutacja nie jest tutaj problemem. Gdyby JS miał klasę Matrix, czy uważasz, że posiadanie *operatora jest nadużyciem ?
dan04

24

Uważam, że JavaScript jest domyślnie globalny jako poważny problem i często jest źródłem błędów, jeśli nie używasz JSLint lub podobnego


2
Domyślnie globalny? Cieszę się, że nie używam JS ...
Anto

5
W rzeczywistości jest to bardzo fajny język z kilkoma złymi opcjami do wyboru. Jest to główny, jeśli nie podasz zakresu zmienną, obliczy ona zakres jako globalny. Dobrą rzeczą jest to, że korzystając z programu Jslint Douga Crockforda można złapać ten błąd i wiele innych.
Zachary K

1
Po prostu użyj, vargdy deklarujesz zmienną i jesteś gotowy. I nie mów mi, że to zbyt dużo pisania, ponieważ Java zmusza cię do dwukrotnego zadeklarowania wszystkich typów i nikt nie narzeka, że ​​to kiepski wybór.
davidk01

3
@ davidk01: Ludzie narzekają na to. Podobnie ludzie narzekali na konieczność deklarowania std::map<KEY, VALUE>::const_iteratorzmiennych w C ++ na tyle, że autosą dodawane do tego języka.
dan04,

1
"use strict"dyrektywy, dodał w ES5 zmienia referencje nielegalnej w błąd.
Sean McMillan,

22

Preprocesor w C i C ++ jest ogromną kludge, tworzy abstrakcje, które przeciekają jak sita, zachęca do kodowania spaghetti poprzez gniazda #ifdefinstrukcji szczura i wymaga strasznie nieczytelnych ALL_CAPSnazw, aby obejść jego ograniczenia. Źródłem tych problemów jest to, że działa na poziomie tekstowym, a nie na poziomie składniowym lub semantycznym. Powinien zostać zastąpiony funkcjami języka rzeczywistego w różnych przypadkach użycia. Oto kilka przykładów, choć wprawdzie niektóre z nich rozwiązano w C ++, C99 lub nieoficjalnych, ale de facto standardowych rozszerzeniach:

  • #include powinien zostać zastąpiony prawdziwym systemem modułowym.

  • Funkcje wbudowane i szablony / ogólne mogą zastąpić większość przypadków użycia wywołania funkcji.

  • Do deklarowania takich stałych można użyć pewnego rodzaju funkcji stałej czasowej manifestu / kompilacji. Przedłużenia enumu D świetnie sprawdzają się tutaj.

  • Makra na poziomie drzewa składni mogą rozwiązać wiele różnych przypadków użycia.

  • W przypadku użycia wstrzyknięcia kodu można zastosować miksy łańcuchowe .

  • static iflub versiondo kompilacji warunkowej można użyć instrukcji.


2
@dsimcha: Zgadzam się z tym #includeproblemem, ale system modułowy został wynaleziony ... później! A C i C ++ dążą do maksymalnej kompatybilności wstecznej: /
Matthieu M.

@Matthieu: Tak, systemy modułowe zostały wynalezione posłaniec, ale w każdym razie mówimy o tym z perspektywy czasu.
dsimcha

3
Zgadzam się, że jest to ogromny ból w różnych częściach ciała, ale konstrukcja wieloprzebiegowa ma tę zaletę, że jest prosta: kompilator C nie musi wiele wiedzieć o kontekście działania, zanim będzie mógł z powodzeniem skompilować fragment kodu C . Można to zakwalifikować jako błąd projektowy tylko wtedy, gdy można wykazać, że koszty korzystania z hipotetycznego systemu modułów w samym języku C (np. Klasy podobne do C ++) są zawsze niższe lub porównywalne z obecnym #includehakowaniem opartym na procesorze CPP.
reinierpost

Zgadzam się. Jednak niektórzy uważają, że wstępne przetwarzanie jest dobrą rzeczą i narzekają, że nie jest ono obsługiwane (na przykład) w Javie.
Stephen C,

5
@Stephen: Zgadzam się, że Java z preprocesorem może być lepsza niż Java bez, ale tylko dlatego, że Java nie ma kilku „prawdziwych” funkcji niezbędnych do zastąpienia preprocesora. W językach takich jak D, które zawierają takie funkcje i Python, który zyskuje elastyczność na inne sposoby dzięki dynamice, nie brakuje mi tego ani trochę.
dsimcha,

21

Można wymienić setki błędów w setkach języków, ale IMO nie jest to przydatne ćwiczenie z perspektywy projektowania języka.

Czemu?

Ponieważ coś, co byłoby błędem w jednym języku, nie byłoby błędem w innym języku. Na przykład:

  • Uczynienie z C języka zarządzanego (tj. Zbierającego śmieci) lub ograniczenie pierwotnych typów ograniczyłoby jego przydatność jako półprzenośnego języka niskiego poziomu.
  • Dodanie zarządzania pamięcią w stylu C do języka Java (na przykład w celu rozwiązania problemów związanych z wydajnością) spowodowałoby jego uszkodzenie.

Jest to należy wyciągnąć wnioski, ale lekcje rzadko są jednoznaczne, a ich zrozumieć trzeba zrozumieć technicznych kompromisów ... i historyczny kontekst. (Na przykład nieporęczna implementacja Java generics jest konsekwencją nadrzędnych wymagań biznesowych aby zachować kompatybilność wsteczną).

IMO, jeśli poważnie myślisz o zaprojektowaniu nowego języka, musisz faktycznie korzystać z szerokiej gamy istniejących języków (i uczyć się języków historycznych) ... i zdecydować, jakie są błędy. I należy pamiętać, że każdy z tych języków został zaprojektowany w określonym kontekście historycznym, aby zaspokoić określoną potrzebę.

Jeśli trzeba wyciągnąć ogólne wnioski, są one na poziomie „meta”:

  • Nie można zaprojektować języka programowania, który byłby idealny do wszystkich celów.
  • Nie można uniknąć błędów ... zwłaszcza, gdy patrzy się z tyłu.
  • Wiele błędów jest bolesnych do poprawienia ... dla użytkowników twojego języka.
  • Musisz wziąć pod uwagę pochodzenie i umiejętności odbiorców docelowych; tj. istniejący programiści.
  • Nie możesz zadowolić wszystkich.

9
-1 - języki programowania są zgodne z celami projektowymi. Cechy języka, które działają wbrew tym celom, są wadami projektowymi, chyba że stanowią konieczny kompromis dla jednego z pozostałych celów. Niewiele języków powstaje z zamiarem zadowolenia wszystkich, ale wszystkie języki powinny starać się zadowolić tych ludzi, których zaspokojenie ma na celu przede wszystkim. Tego rodzaju postmodernistyczna poprawność polityczna jest dość trudna w programowaniu badań i rozwoju języka.
Rei Miyasaka,

Chodzi mi o to, że trudno jest uczyć się lekcji bez uwzględnienia celów projektowych.
Stephen C

1
wydaje mi się, że PO uwzględnił już twoją odpowiedź w drugim akapicie pytania.
Aidan Cully,

20

C i C ++ : Wszystkie typy liczb całkowitych, które nic nie znaczą .

Zwłaszcza char. Czy to tekst czy mała liczba całkowita? Jeśli jest to tekst, czy jest to znak „ANSI” czy jednostka kodu UTF-8? Jeśli jest to liczba całkowita, czy jest podpisana czy niepodpisana?

int miał być liczbą całkowitą wielkości „natywnej”, ale w systemach 64-bitowych tak nie jest.

longmoże, ale nie musi być większy niż int. Może, ale nie musi być wielkości wskaźnika. Jest to dość arbitralna decyzja autorów kompilatora, czy jest to wersja 32-bitowa czy 64-bitowa.

Zdecydowanie język lat siedemdziesiątych. Przed Unicode. Przed komputerami 64-bitowymi.


10
C nie został zaprojektowany jako standardowy uniwersalny język, dlatego nie może być błędem projektowym. Został zaprojektowany do modelowania procesora jako przenośnego asemblera, unikając specyficznego dla procesora kodu asemblera. Zostało to jednak naprawione w Javie.

7
Myślę, że większym problemem są nowsze języki, które nadal używają tych samych bezsensownych terminów, mimo że historia pokazuje nam, że to okropny pomysł. Przynajmniej chłopaki C zauważyli swój błąd i stworzyli standardowe typy int.
Mark H

5
Znak nie jest jednostką utf-8. Przechowywanie znaku utf-8 może zająć więcej niż 8 bitów. C nie jest językiem lat 70., używam go teraz do projektu (dobrowolnie).
dan_waterworth

4
C to niewiele więcej niż abstrakcja wysokiego poziomu procesora PDP-11. Na przykład inkrementacja przed i po była bezpośrednio wspierana przez PDP-11.
bit-twiddler

5
To strasznie błędna odpowiedź. Po pierwsze, C i C ++ nie są wymienne. Po drugie, specyfikacja języka wyraźnie określa, co to jest znak - Obiekt zadeklarowany jako typ char jest wystarczająco duży, aby przechowywać dowolny element podstawowego zestawu znaków wykonania. . Po trzecie, C nie jest „językiem lat 70-tych”, jest to język, który żyje blisko sprzętu i jest prawdopodobnie językiem, który ostatecznie pozwala wszystkim twoim abstrakcjom na wysokim poziomie mieć sens dla procesora. Wychodzisz jako osoba, która zna tylko języki wysokiego poziomu i nie docenia tego, jak rzeczy naprawdę działają. -1
Ed S.

18

null.

Jego wynalazca, Tony Hoare, nazywa to „błędem miliarda dolarów” .

Został wprowadzony w ALGOL w latach 60. i istnieje obecnie w większości powszechnie używanych języków programowania.

Lepszą alternatywą, używaną w takich językach jak OCaml i Haskell, jest może . Ogólna idea jest taka, że ​​odwołania do obiektów nie mogą być zerowe / puste / nie istnieją, chyba że istnieje wyraźne wskazanie, że mogą być.

(Chociaż Tony jest niesamowity w swojej skromności, myślę, że prawie każdy popełniłby ten sam błąd, a on po prostu był pierwszy).


Nie zgadzaj się, nawet z wynalazcą !!! null jest pustą wartością dla typu danych wskaźnika / odniesienia. Ciągi mają pusty ciąg, zestawy mają pusty zestaw (Pascal empty set = []), liczby całkowite mają 0. Większość języków programowania, które używają null / nil / cokolwiek, jeśli poprawnie przypisano zmienną, można zapobiec błędowi null.
umlcat,

4
@ user14579: Każdy język, który obsługuje dowolny zestaw, ciąg lub tablicę ma {}, ale taki jest nadal semantycznie odpowiedni i nie zawiedzie się, chyba że masz już coś, co może spowodować błąd związany z tablicą - ale to już inny problem. Możesz przetworzyć pusty ciąg na wielkie litery wszystkich znaków, co spowoduje powstanie pustego ciągu. Próbujesz tego samego na łańcuchu zerowym i bez odpowiedniego rozważenia nastąpi awaria. Problem polega na tym, że ta właściwa uwaga jest żmudna, często zapomniana i utrudnia pisanie funkcji jednoznacznych (tj. Lambdas).
Rei Miyasaka,

1
Zarabiam pieniądze za każdym razem, gdy wpisuję null ... no tak, ktoś traci pieniądze za każdym razem, gdy wpisuję null. Z wyjątkiem tego czasu.
kevpie 12.03.11

3
@umlcat - gdy masz języki z dopasowaniem wzorca, takie jak Ocaml, Haskell i F #, używając Może x | Żaden wzorzec nie pozwala zapomnieć o pustej wielkości w czasie kompilacji. Żadna sztuczka w czasie kompilacji nie może wykryć błędu w językach, w których ustalony idiom to null. Ponieważ musisz jawnie zdecydować, aby nie zajmować się przypadkiem zerowym w językach, które mają monadę Być może i Niektóre, mają one poważną przewagę nad podejściem „zerowym”.
JasonTrue

1
@Jason - lubię myśleć o maybeopt-in zerowej, podczas gdy wyjątek null to opt-out. Oczywiście jest kilka rzeczy do powiedzenia na temat różnicy między błędami środowiska wykonawczego a błędami czasu kompilacji, ale sam fakt, że null jest zasadniczo wstrzykiwaniem zachowania, jest sam w sobie warty odnotowania.
Rei Miyasaka,

14

Mam wrażenie, że ludzie, którzy zaprojektowali PHP, nie używali normalnej klawiatury, nawet nie używają klawiatury colemak, ponieważ powinni byli zrozumieć, co robią.

Jestem programistą PHP. PHP nie jest fajne do pisania.

Who::in::their::right::mind::would::do::this()? ::Operator wymaga zmiany trzymającego i potem dwa naciśnięcia przycisków. Co za strata energii.

Chociaż-> to-> jest-> nie-> dużo-> lepiej. Wymaga to również trzech naciśnięć klawiszy z przesunięciem pomiędzy dwoma symbolami.

$last = $we.$have.$the.$dumb.'$'.$character. Znak dolara jest używany wiele razy i wymaga rozciągnięcia nagrody aż do samej góry klawiatury oraz naciśnięcia klawisza Shift.

Dlaczego nie mogli zaprojektować PHP do używania kluczy, które są znacznie szybsze do pisania? Dlaczego we.do.this()vars nie mogą zacząć mieć klucza, który wymaga tylko jednego naciśnięcia klawisza - lub wcale (JavaScript) i po prostu wstępnie zdefiniować wszystkie vary (tak jak i tak muszę zrobić dla E_STRICT)!

Nie jestem powolną maszynistką - ale to tylko kiepski wybór.


Perl podziela ten ból.
Daenyth

2
Podobnie C ++ i z jakiegoś niewytłumaczalnego dziwnego powodu PowerShell.
Rei Miyasaka,

2
Użyj wydajniejszego edytora i zdefiniuj własne sekwencje klawiszy dla tych operatorów.
kevin cline,

1
I::have::nothing::against::this->at.all()
Mateen Ulhaq,

1
Może nie używają klawiatury qwerty. $ i: nie trzeba naciskać klawisza Shift na wszystkich klawiaturach jak azerty.
Arkh

13

Korzystanie z formularzy inspirowanych pulpitem w asp.net .

Zawsze czułem krówki i przeszkadzało w działaniu sieci. Na szczęście asp.net-mvc nie cierpi w ten sam sposób, choć dzięki tej inspiracji Ruby itp.


18
Czy to nie jest biblioteka?
nikie

@nikie, to dobra uwaga;)
dove

1
@nikie Właściwie, oparty na XML kod ASPX jest językiem, więc możesz go przekręcić do pracy. : D
CodexArcanum

2
Myślę, że prawdziwy problem z ASP.NET polega na tym, jak bardzo stara się ukryć szczegóły programistyczne w Internecie. Rzeczywiście w ASP.NET dzieje się kilka naprawdę schludnych, przydatnych rzeczy, ale musisz walczyć tak ciężko i kopać tak głęboko, aby się do tego dostać.
CodexArcanum

1
Z drugiej strony istnieją tysiące prostych i udanych aplikacji do gromadzenia danych, które zostały połączone za pomocą „klasycznej” aplikacji komputerowej. Jedyną złą rzeczą było to, że do MVC jedyną opcją Microsoft były formularze systemu Windows.
ElGringoGrande

13

Dla mnie to jest PHP absolutny brak „s nazewnictwa i zamawiania argumentem konwencji w standardowej bibliotece.

Chociaż konieczność JASS unieważnienia referencji po zwolnieniu / usunięciu referencyjnego obiektu (lub referencja wyciekłaby i utracono by kilka bajtów pamięci) jest poważniejsza, ale ponieważ JASS jest językiem jednofunkcyjnym, nie jest to aż tak istotne.


9
Brak konwencji w stdlib PHP nie jest wadą projektową języka .

3
@delnan: Brak konwencji wynika z tego, jak zaprojektowano PHP i dlatego ma wiele wspólnego z projektowaniem języka. Nie jest też dla mnie jasne, że istnieje wyraźne rozróżnienie między bibliotekami a językiem. Szczególnie Lisp może poszczycić się tradycją ładowania jednego języka na inny.
btilly,

1
Naprawdę niezwykłą rzeczą w JASS było to, że liczył referencje na uchwytach, ale nie wyczyściłby ich, gdyby nie zostały ręcznie zniszczone (a interfejs graficzny stworzył funkcje, które przeciekły pamięć wszędzie)!
Craig Gidney

13

Największą wadą projektową, z jaką się spotykam, jest to, że Python nie został zaprojektowany jak Python 3.x na początek.


1
Cóż, nawet Guido nie może uzyskać wszystkiego od razu ...

5
@ delnan, och, wiem, a python <3 jest wciąż zadziwiająco dobrym językiem, ale trochę denerwujące jest posiadanie lepszego języka w postaci python 3.x, którego nie mogę używać, ponieważ psuje wszystkie moduły, które Potrzebuję.
dan_waterworth

Kontynuuj lobbowanie za modułami Python 3.x! W międzyczasie będę nadal pisać w 2.5.4. Dzięki SO przypomniałem sobie, że 3.x żyje i ma się dobrze.
kevpie 12.03.11

@kevpie Najpierw lobby, aby dodać kompilację warunkową do Pythona, aby ułatwić przejście dla opiekunów bibliotek. 2to3 nie jest rozwiązaniem możliwym do utrzymania w perspektywie długoterminowej.
Evan Plaice,

12

Rozpad tablicy w C i w konsekwencji C ++.


Chciałbym też mieć odpowiednią obsługę macierzy. W C ++ można zapobiec rozpadowi za pomocą składni absconów i szablonów ... ale jest to raczej hack: /
Matthieu M.

1
Zauważ, że jest to powód, dla którego C ++ musi mieć oddzielne deletei delete[]operatory.
dan04

Zawsze możesz umieścić tablicę w strukturze i przekazać ją według wartości, jeśli chcesz, ale zwykle jest to bardziej niezręczne niż pierwotny problem. W C ++ zwykle można uniknąć konieczności używania tablic.
David Thornley,

2
Przynajmniej w przypadku C argumentem przeciwko właściwej obsłudze tablic jest „sprawdzanie granic tablic jest kosztowne”, szczególnie biorąc pod uwagę sposób działania arytmetyki wskaźnika C.
Stephen C

@Stephen C: Jakie sprawdzanie granic tablic ma związek z rozkładem tablic?
Nemanja Trifunovic

11

Typy pierwotne w Javie.

Łamają zasadę, że wszystko jest potomkiem java.lang.Object, co z teoretycznego punktu widzenia prowadzi do dodatkowej złożoności specyfikacji językowej, a z praktycznego punktu widzenia sprawiają, że korzystanie z kolekcji jest niezwykle nużące.

Autoboxing pomógł złagodzić praktyczne wady, ale kosztem uczynienia specyfikacji jeszcze bardziej skomplikowaną i wprowadzenia grubej skórki banana: teraz możesz uzyskać wyjątek wskaźnika zerowego od czegoś, co wygląda jak prosta operacja arytmetyczna.


Spowodowałoby to straszny problem z wydajnością, gdybyś usunął typy prymitywne. A autoboxing można łatwo zepsuć, więc nic nie poprawia.
deadalnix

W tym czasie była to rozsądna decyzja projektantów Java. Wzrost wydajności, biorąc pod uwagę maszyny / maszyny wirtualne dostępne w latach 90., przewyższał koncepcyjne zalety ujednolicenia wszystkiego wokół java.lang.Object.
mikera

10

Znam Perla najlepiej, więc wybiorę to.

Perl próbował wielu pomysłów. Niektóre były dobre. Niektóre były złe. Niektóre były oryginalne i nie zostały powszechnie skopiowane z dobrego powodu.

Jednym z nich jest idea kontekstu - każde wywołanie funkcji odbywa się w kontekście listowym lub skalarnym i może robić zupełnie różne rzeczy w każdym kontekście. Jak wskazałem na http://use.perl.org/~btilly/journal/36756, komplikuje to każdy interfejs API i często prowadzi do subtelnych problemów projektowych w kodzie Perla.

Kolejnym jest pomysł tak kompletnego wiązania składni i typów danych. Doprowadziło to do wynalezienia wiązania, które pozwala maskować obiekty jako inne typy danych. (Możesz również osiągnąć ten sam efekt za pomocą przeciążenia, ale remis jest bardziej powszechnym podejściem w Perlu).

Innym częstym błędem popełnianym przez wiele języków jest rozpoczęcie od dynamicznego określania zakresu, a nie leksykalnego. Trudno później cofnąć tę decyzję projektową i prowadzi to do długotrwałych brodawek. Klasyczny opis tych brodawek w Perlu to http://perl.plover.com/FAQs/Namespaces.html . Zauważ, że zostało to napisane zanim Perl dodał ourzmienne i staticzmienne.

Ludzie słusznie nie zgadzają się na temat pisania statycznego i dynamicznego. Osobiście lubię dynamiczne pisanie. Jednak ważne jest, aby mieć wystarczającą strukturę, aby pozwolić na złapanie literówek. Perl 5 dobrze sobie z tym radzi ze ścisłością. Ale Perl 1-4 źle to zrozumiał. Kilka innych języków ma kontrolery kłaczków, które robią to samo co surowe. Dopóki jesteś dobry w egzekwowaniu sprawdzania kłaczków, jest to dopuszczalne.

Jeśli szukasz więcej złych pomysłów (wiele z nich), naucz się PHP i przestudiuj jego historię. Moim ulubionym błędem z przeszłości (dawno temu naprawionym, ponieważ prowadził do tylu dziur w zabezpieczeniach) było domyślne, pozwalające każdemu ustawić dowolną zmienną poprzez przekazanie parametrów formularza. Ale to nie jest jedyny błąd.


5
Tak, Perl ma wiele błędów, ponieważ ludzie, którzy go zbudowali, próbowali nowych pomysłów, a kiedy to robisz, często mylicie się. (Perl ma też kilka bardzo dobrych rzeczy i jest standardem dla Regexps, który wszyscy skopiowali)
Zachary K

@ zachary-k: Całkowicie się zgadzam. Próbowałem to wyjaśnić, zanim zacząłem rozwiązywać problemy.
btilly,

4
Lisps był początkowo dynamicznie skalowany, az czasem zmienił się w leksykalny (przynajmniej w Scheme i Common Lisp). Zmiana nie jest niemożliwa.
David Thornley,

4
@ David-Thornley: Jest to niemożliwe, chyba że gdzieś poświęcisz kompatybilność wsteczną. Program zawsze miał zasięg leksykalny. Common Lisp miał zasięg leksykalny od czasu, gdy został ustandaryzowany, ale różne społeczności Lisp miały swoje trudności z jego przyjęciem. Emacs Lisp nadal używa dynamicznego określania zakresu, mimo że od dawna istnieje chęć jego zmiany.
btilly,

1
BTW, wiele rzeczy, których ludzie nie lubią Perla, nie zostały wynalezione w Perlu, ale wzięte z innych języków, głównie z powłoki Bourne'a.
reinierpost

10

Niejednoznaczność JavaScript w blokach kodu i literałach obiektów.

  {a:b}

może być blokiem kodu, gdzie ajest etykietą i bwyrażeniem; lub może zdefiniować obiekt z atrybutem, aktóry ma wartośćb


Właściwie podoba mi się to w JavaScript. Prostota struktury językowej jest przyjemna, a cel powinien być oczywisty, jeśli programista wie, co robi.
Xeoncross,

2
Xeoncross: Ogólnie nie lubię dwuznaczności. W tym przypadku jest to oczywiste dla programisty, ale eval () potrzebuje dodatkowych nawiasów.
user281377,

2
@ammoQ: To oczywiste? Co to jest? Obiekt czy blok kodu?
konfigurator

konfigurator: Oczywiście obiekt. Żadna zdrowa osoba nie użyłaby etykiety o nazwie a.
user281377,

10

Wrócę do FORTRAN i niewrażliwości na białe znaki.

Przenikało specyfikację. ENDMiał karty, które zostaną zdefiniowane jako karta z „E”, „N”, i „D” w tej kolejności w kolumnach 7-72, a nie innego nonblanks, zamiast karty z „End” we właściwym kolumny i nic więcej.

Doprowadziło to do łatwego zamieszania składniowego. DO 100 I = 1, 10była instrukcją sterującą pętlą, podczas gdy DO 100 I = 1. 10była instrukcją, która przypisała wartość 1.1 do zmiennej o nazwie DO10I. (Przyczynił się do tego fakt, że zmienne można tworzyć bez deklaracji, a ich typ zależy od ich pierwszej litery.) W przeciwieństwie do innych języków, nie było sposobu na użycie spacji do oddzielenia tokenów, aby umożliwić ujednoznacznienie.

Umożliwiło to także innym osobom pisanie naprawdę mylącego kodu. Istnieją powody, dla których ta funkcja FORTRAN nigdy nie została powtórzona.


1
W języku, w którym można na nowo zdefiniować literały, jest to najgorszy przykład - mam na myśli to, że spowodował tylko awarię jednego małego statku kosmicznego
Martin Beckett

Na początku możesz napisać DAMNATION zamiast DIMENSION, i to zadziała.
Mike Dunlavey,

Nadal jest nauczany przez osoby spoza CS. Nadal mam do czynienia z tymi, którzy: a) walczą z deklaracjami, b) walczą z białymi spacjami, c) jak „linie kontynuacji”, d) używają nazw 6-znakowych lub 4, d) są zakłopotani, gdy widzą (test ? a : b), e) nalegają przy użyciu **, f) nie radzi sobie z rozróżnianiem wielkości liter. Większość z nich była spowodowana uderzeniami klawiszy w latach 50.
Mike Dunlavey,

1
@Martin Beckett - redefinicja literałów w FORTRAN była raczej błędem kompilatora niż funkcją językową. Z pewnością nie była to celowa funkcja językowa.
Stephen C

1
@oosterwal: Z pewnością tak. Mogę się mylić, ale niejasno pamiętam definicję języka opartą na kartach uderzeń. Były wówczas głównym sposobem wprowadzania programów FORTRAN, a pomysł 80-kolumnowej linii z zarezerwowanymi kolumnami 73-80 pochodzi z kart dziurkowanych.
David Thornley,

9

Jednym z największych problemów z BASIC-em był brak dobrze zdefiniowanej metody rozszerzenia języka poza jego wczesne środowiska, co doprowadziło do szeregu całkowicie niekompatybilnych implementacji (i prawie nieistotnej postfaktycznej próby jakiejkolwiek standaryzacji).

Niemal każdy język zostanie upowszechniony przez jakiegoś szalonego programistę. Lepiej na początku zaplanować użycie tego ogólnego celu na wypadek, gdyby szalony pomysł się pojawił.


2
+1: Każdy język bez odpowiednich modułów i bibliotek jest błędem, który czeka. COBOL również cierpiał z tego powodu, prowadząc do osobliwych wariantów, które nie są kompatybilne.
S.Lott,

8

Wierzę w DSL (języki specyficzne dla domeny), a jedną rzeczą, którą cenię w języku, jest to, że pozwala mi to zdefiniować DSL na nim.

W Lisp są makra - większość ludzi uważa to za dobrą rzecz, podobnie jak ja.

W C i C ++ są makra - ludzie narzekają na nie, ale mogłem ich użyć do zdefiniowania DSL.

W Javie zostały pominięte (a zatem w języku C #), a ich brak został uznany za cnotę. Jasne, że to pozwala na inteligencję, ale dla mnie to tylko dzieło . Aby wykonać DSL, muszę rozwinąć ręcznie. Jest to ból i sprawia, że ​​wyglądam jak zły programista, mimo że pozwala mi zrobić o wiele więcej przy tonie mniejszej ilości kodu.


4
Zgadzam się, że każdy język bez przyzwoitych makr jest jedną wielką nieusuwalną wadą projektową. Ale co rozumiesz przez „ zostały pominięte ”? Preprocesor C nie był żadnym porządnym systemem makr. Java nie pochodzi z żadnego odpowiedniego języka z makrami.
SK-logic

1
Możesz napisać swoją DSL w zewnętrznym języku przetwarzania makr (np. M4, powiedzmy, wśród wielu innych).
PO PROSTU MOJA poprawna OPINIA,

4
@SK: Nie powiem, że preprocesor C jest porządnym systemem makr w porównaniu do Lisp (na przykład). Ale w porównaniu do niczego jest niezwykle przydatny.
Mike Dunlavey,

4
@reinierpost: Myślę o rzeczach, które mógłbym zrobić w Lisp, takich jak wprowadzenie struktur kontrolnych, takich jak wykonywanie różnicowe i powrót. Można to zrobić za pomocą makr Lisp. W C / C ++ mogłem wykonywać różnicowanie z makrami C (i małą dyscypliną programistyczną), ale nie cofać się. Z C # nie mogę zrobić ani jednego. W zamian dostaję rzeczy takie jak intellisense. BFD.
Mike Dunlavey,

1
@David: W ten sposób miałem makro do zawinięcia zwykłego kodu, takie jak lista instrukcji. Wziąłby cdrlistę i utworzyłby z niej zamknięcie lambda (tj. Kontynuację) i przekazałby ją jako argument do carlisty. Zrobiono to oczywiście rekurencyjnie i „zrobiłoby to dobrze” w przypadku warunkowych, pętli i wywołań funkcji. Wtedy funkcja „wyboru” właśnie zmieniła się w normalną pętlę. Nie ładna, ale solidna. Problem polega na tym, że bardzo łatwo jest tworzyć zbyt zagnieżdżone pętle.
Mike Dunlavey,

7

Oświadczenia , w każdym języku, który je ma. Nie robią nic, czego nie można zrobić z wyrażeniami i uniemożliwiają robienie wielu rzeczy. Istnienie ?:operatora trójskładnikowego jest tylko jednym z przykładów próby obejścia go. W JavaScript są szczególnie denerwujące:

// With statements:
node.listen(function(arg) {
  var result;
  if (arg) {
    result = 'yes';
  } else {
    result = 'no';
  }
  return result;
})

// Without:
node.listen(function(arg) if (arg) 'yes' else 'no')

Jestem tu zdezorientowany: czy chcesz po prostu prostszego sposobu robienia rzeczy?
TheLQ

2
Poprawny. Wyrażenia na wszystko.
wspaniałomyślny

1
Lisp dobrze na to działa.
David Thornley,

1
@ SK-logic: Podejrzewam, że oświadczenia zostały ślepo odziedziczone z języka maszynowego przez FORTRAN, ALGOL i COBOL.
David Thornley,

1
Jestem prawie pewien, że język maszynowy jest wspólnym przodkiem, a to tylko odzwierciedlenie faktu, że współczesne komputery oparte na architekturze von Neumanna wykonują instrukcje sekwencyjnie i modyfikują stan. Ostatecznie, gdy nastąpi IO, pojawią się wyrażenia, które nie dostarczają znaczących danych, więc instrukcje nie są całkowicie bezużyteczne w wskazywaniu semantycznie, że jakiś kod ma tylko skutki uboczne. Nawet języki, które zamiast unitwyrażeń mają pojęcie typu (aka ()), zwracają szczególną uwagę na to, aby nie rzucały ostrzeżeń ani nie zachowywały się dziwnie.
Rei Miyasaka,

6

Dla mnie jest to problem projektowy, który nęka wszystkie języki wywodzące się z C; mianowicie „ zwisające inne ”. Ten problem gramatyczny powinien zostać rozwiązany w C ++, ale został przeniesiony do Java i C #.


3
Jednym z głównych celów C ++ była pełna wsteczna kompatybilność z C. Gdyby drastycznie zmienili zachowanie semantyczne, być może nie przyłapałby się tak, jak miało to miejsce (a przynajmniej taka była wówczas myśl)
Ed S.

2
@Ed S. jednakże wyeliminowanie problemu „wiszącego innego” można było osiągnąć poprzez wyeliminowanie produkcji gramatycznej <compound_statement> (alias <block>) i włączenie nawiasów klamrowych do warunkowych i iteracyjnych struktur kontrolnych, tak jak wtedy, gdy dodano strukturę kontrolującą obsługę wyjątków try / catch. Nie ma usprawiedliwienia dla nie korygowania tej dwuznaczności gramatycznej w Javie i C #. Obecnie obronnym rozwiązaniem tej gramatycznej dwuznaczności jest uczynienie każdej instrukcji następującej po warunkowej lub iteracyjnej instrukcji kontroli złożoną instrukcją.
bit-twiddler

1
Co przez to rozumiesz? To nie jest „problem gramatyczny” (jest całkowicie jednoznaczny). Jak byś to „rozwiązał”? Właściwie uważam, że reguły w C są zadowalające. Prawdopodobnie tylko składnia podobna do Pythona (= znaczące wcięcie) może naprawdę rozwiązać ten problem. Co więcej, jestem bardzo szczęśliwy, że współczesne języki nie wymagają nawiasów klamrowych. Zgadzam się, że wszystkie składnie podobne do C są do bani, ale wiszące, bo to najmniej ich problem.
Konrad Rudolph,

1
Kontynuacja: Myślę, że użycie wcięcia w Pythonie jako sposobu na określenie listy instrukcji jest dziwne poza wszelką wiarą. Ta technika narusza zasadę „rozdzielania obaw” poprzez ścisłe sprzężenie skanowania leksykalnego z analizą składni. Gramatyka bezkontekstowa powinna być analizowana bez wiedzy o układzie źródła.
bit-twiddler

3
@ bit-twiddler: Nie, nie ma. Lexer Pythona po prostu konwertuje białe znaki do odpowiednich tokenów INDENT i DEDENT. Po zakończeniu Python ma dość konwencjonalną gramatykę ( docs.python.org/reference/grammar.html ).
dan04

6

Myślę, że wszystkie dotychczasowe odpowiedzi wskazują na jedno niepowodzenie wielu języków głównego nurtu:

Nie ma możliwości zmiany języka podstawowego bez wpływu na kompatybilność wsteczną.

Jeśli to zostanie rozwiązane, prawie wszystkie inne uchwyty mogą zostać rozwiązane.

EDYTOWAĆ.

można to rozwiązać w bibliotekach, stosując różne przestrzenie nazw, i można sobie wyobrazić zrobienie czegoś podobnego dla większości rdzeni języka, chociaż może to wtedy oznaczać, że trzeba obsługiwać wiele kompilatorów / tłumaczy.

Ostatecznie nie sądzę, że wiem, jak to rozwiązać w sposób całkowicie zadowalający, ale to nie znaczy, że rozwiązanie nie istnieje lub że nie można zrobić więcej


1
Jak poszedłbyś na „rozwiązanie” tego?
Bjarke Freund-Hansen

Nie jestem pewien, czy da się to całkowicie rozwiązać - oczywiście pomaga to trzymać się poza językiem podstawowym i w standardowej bibliotece, więc myślę, że postaram się to posunąć jak najdalej
jk.

1
Czy przez kompatybilność wsteczną masz na myśli, że nowsze kompilatory powinny być w stanie skompilować stary kod?
Rei Miyasaka,

Mam na myśli, że nowsze kompilatory nie powinny zmieniać znaczenia starego kodu, brak kompilacji byłby podzbiorem tego
jk.

w większości przypadków, gdy dana funkcja nie istnieje lub chce się zmienić, ludzie tworzą nowy język w oparciu o poprzedni. C z klasami => C ++
umlcat


4

Zarówno Java, jak i C # mają irytujące problemy ze swoimi systemami typów ze względu na chęć zachowania kompatybilności wstecznej podczas dodawania generycznych. Java nie lubi mieszać ogólnych i tablic; C # nie zezwala na niektóre przydatne podpisy, ponieważ nie można używać typów wartości jako granic.

Rozważ to jako przykład tego ostatniego

public static T Parse <T> (Type <T> type, string str) gdzie T: Enum
obok lub zastępując
publiczny obiekt statyczny Parse (typ typu, ciąg znaków)
w Enum klasie pozwoli
MyEnum e = Enum.Parse (typeof (MyEnum), str);
zamiast tautologicznego
MyEnum e = (MyEnum) Enum.Parse (typeof (MyEnum), str);

tl; dr: pomyśl o polimorfizmie parametrycznym, kiedy zaczniesz projektować swój system typów, a nie po opublikowaniu wersji 1.


2
Niemożność ograniczenia typów do wyliczania jest denerwująca w języku C #, ale możesz w pewnym sensie obejść to w ten sposób MyMethod<T>(T value) where T : struct, IComparable, IFormattable, IConvertible Ale wciąż musisz przetestować wyliczenie i jest to hack. Myślę, że większy brak generycznych C # to brak obsługi wyższych rodzajów, co naprawdę otworzyłoby język na kilka fajnych koncepcji.
CodexArcanum

4

Wydaje mi się, że otwieram się na płomienie, ale naprawdę nie znoszę możliwości przekazywania zwykłych starych typów danych przez odwołanie w C ++. Tylko trochę nienawidzę być w stanie przekazywać złożone typy przez odniesienie. Jeśli patrzę na funkcję:

void foo()
{
    int a = 8;
    bar(a);
}

Z punktu wywoławczego nie ma sposobu, aby stwierdzić, że barw zupełnie innym pliku można zdefiniować:

void bar(int& a)
{
    a++;
}

Niektórzy mogą twierdzić, że robienie czegoś takiego może być po prostu złym projektem oprogramowania i nie winić za to języka, ale nie podoba mi się, że język pozwala ci to zrobić w pierwszej kolejności. Używanie wskaźnika i wywoływanie

bar(&a);

jest o wiele bardziej czytelny.


+1 Nie zgadzam się z tobą, ale doceniam twoje rozumowanie.
Jon Purdy,

@Jon Byłbym bardzo zainteresowany tym, co myślisz. Czy masz widok „nie obwiniaj języka”?
Jeff

6
@Jeff: Z jednej strony głównym powodem, dla którego semantyka odwołań dotarła do C ++, było przeciążenie operatora, dla którego jednolite zachowanie odniesienia ma po prostu sens. Co ważniejsze, C ++ ma być wszechstronny i zapewniać bardzo szczegółowe funkcje, nawet jeśli powoduje to znaczne ryzyko błędu programisty. Tak, przynajmniej w tym konkretnym przypadku, nie obwiniaj języka. Wolę być w stanie popełniać błędy, niż pozwolić, by język mi przeszkadzał.
Jon Purdy,

@Jon zgodził się, że bardzo dziwne byłoby, gdyby podanie przez odniesienie dotyczyło wszystkiego oprócz POD. Wolałbym, gdyby tej opcji całkowicie nie było w C ++ jako alternatywie, ale możemy się zgodzić :). Dzięki za wkład!
Jeff

Java wydaje się nie lubić wskaźników tak bardzo jak ty.
Mateen Ulhaq,

4

ZMIENIAĆ

Kiedy nauczyłem się języka COBOL, instrukcja ALTER wciąż była częścią standardu. Krótko mówiąc, to oświadczenie pozwoli ci modyfikować wywołania procedur w czasie wykonywania.

Niebezpieczeństwo polegało na tym, że można było umieścić tę instrukcję w jakiejś niejasnej części kodu, do której rzadko uzyskiwano dostęp i która potencjalnie mogła całkowicie zmienić przebieg reszty programu. Dzięki wielu instrukcjom ALTER możesz praktycznie uniemożliwić sprawdzenie, co robił Twój program w dowolnym momencie.

Mój instruktor uniwersytecki bardzo stanowczo stwierdził, że gdyby kiedykolwiek zobaczył to oświadczenie w którymkolwiek z naszych programów, automatycznie nas wyrzuci.


Ma jednak dobre przypadki użycia - stubowanie lub zapamiętywanie. Zamiast pisać v() { if (not alreadyCalculatedResult) { result = long(operation); alreadyCalculatedResult = true; } result; }mówiszv() { result = long(operation); v = () => result; result; }
konfigurator

4

Najgorszy grzech języka programowania nie jest dobrze zdefiniowany. Przypadek, który pamiętam, to C ++, który początkowo:

  1. Został tak źle zdefiniowany, że nie można było uzyskać programu do kompilacji i uruchomienia na podstawie książek lub przykładów.
  2. Po dostosowaniu programu do kompilacji i uruchomieniu w jednym kompilatorze i systemie operacyjnym, będziesz musiał zacząć od nowa, jeśli zmienisz kompilatory lub platformy.

Jak pamiętam, zajęło około dekady zdefiniowanie C ++ na tyle dobrze, aby uczynić go tak niezawodnym zawodowo jak C. Jest to coś, co nigdy nie powinno się powtórzyć.

Coś innego, co uważam za grzech (czy powinienem udzielić innej odpowiedzi?), Ma więcej niż jeden „najlepszy” sposób na wykonanie jakiegoś wspólnego zadania. Jest tak w przypadku (ponownie) C ++, Perla i Ruby.


1
Nie rozumiem, jak uniknąć źle zdefiniowanego języka w ewoluującym języku. Lub, jeśli o to chodzi, w z góry zaprojektowanym języku, w którym oryginalny projektant nie zauważył kilku ważnych punktów (takich jak Pascal).
David Thornley,

@David Thornley Dobrze zdefiniowany jest dobrze zdefiniowany. Wytrzymałość na błędy, większość projektantów języków programowania zaczyna od samego początku. Narzędzia mogą sprawdzić, czy gramatyka jest jednoznaczna, gdy jest kompletna (C ++ wymaga co najmniej trzech gramatyk), a semantyka powinna być określona dla standardowych implementacji.
Apalala,

Zgadzam się, że dobrze zdefiniowane języki są możliwe, ale tak się nie stanie w ewoluującym języku, takim jak pre-Standard C ++. Alternatywą jest to, że każdy język jest dokładnie zaprojektowany przed wydaniem, i niekoniecznie jest to sposób na uzyskanie najlepszych języków. Powiedziałbym, że większość projektantów języków programowania na początku popełnia błędy, ponieważ projektowanie języka jest niezwykle skomplikowane.
David Thornley,

Myślę, że mam problem ze zrozumieniem, co rozumiesz przez „dobrze zdefiniowany”. Czy narzekasz, że różne kompilatory C ++ nie skompilowały tego samego języka?
Sean McMillan,

3

Klasy w C ++ są pewnego rodzaju wzorcem wymuszonego projektowania w języku.

W czasie wykonywania praktycznie nie ma różnicy między strukturą a klasą, a zrozumienie, jaka jest prawdziwa prawdziwa przewaga programistyczna „ukrywania informacji”, jest tak mylące, że chcę ją tam umieścić.

Będę wdzięczny za to, ale w każdym razie kompilatory C ++ są tak trudne do napisania, że ​​ten język jest jak potwór.


2
Ukrywanie informacji jest ważne, ponieważ pozwala ukryć szczegóły implementacji, które mogą ulec zmianie, z dostępnych części interfejsu API („interfejsu użytkownika” interfejsu API), dzięki czemu zmiany w programie stają się łatwiejsze i mniej bolesne.
Anto

1
Interfejs API ... nie, poważnie, nie kupuję tego.
Jokoon

3
Ta różnica nie jest najbardziej obrzydliwą częścią C ++, nawet nie jest bliska. Jedyną różnicą jest domyślny modyfikator dostępu (publiczny dla struktur, prywatny dla klas). C ++ jest okropnym, potwornym językiem, ale na pewno nie w tej części.
SK-logic

sk-logic: cóż, można powiedzieć, że horrory zaczynają się właśnie tam.
Jokoon

2
Ukrywanie informacji jest dobre; można znaleźć dyskusje na ten temat. Jedyną znaną książką o oprogramowaniu, którą wymyśliłem, była przeciwna to „The Mythical Man-Month” Brooksa, który później uznał za największy błąd w książce. Jeśli nie rozumiesz zalet, tak naprawdę nie masz kwalifikacji, aby wydawać osąd.
David Thornley,

3

Chociaż każdy język ma swoje wady, żaden nie jest uciążliwy, gdy się o nich dowiesz. Z wyjątkiem tej pary:

Złożona składnia w połączeniu z trudnymi interfejsami API

Dotyczy to szczególnie języka takiego jak Objective-C. Składnia jest nie tylko złożona, ale interfejs API używa nazw funkcji takich jak:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

Jestem za byciem jawnym i niejednoznacznym, ale to jest śmieszne. Za każdym razem, gdy siadam przy xcode, czuję się jak n00b, co jest naprawdę frustrujące.


Składnia celu C jest w przeważającej mierze złożona? Nie widziałeś C ++? I faktycznie istnieje nazwa metody tableView:cellForRowAtIndexPath:, która moim zdaniem jest bardzo opisowa.
prawej

Naucz się pisać na klawiaturze.
finnw

2
  1. podpisane znaki w C - obrzydliwość wymyślona, ​​aby umożliwić matematykom duże zbiory małych przedmiotów
  2. Używanie skrzynki do przenoszenia treści semantycznej - znowu dla matematyków, którzy nie muszą rozmawiać i nigdy nie mają wystarczająco dużo miejsca na swoje formuły
  3. Zadanie Let / Plain vs. Set przypisanie w dialektach podstawowych - myślę, że nie ma tu matematyków

Zgubiłem się w komentarzu do podpisanych znaków, czy możesz to wyjaśnić?
Winston Ewert

1
Dla człowieka koncepcja (niez) podpisanych znaków i konieczność poinformowania kompilatora, aby domyślnie używał niepodpisanych znaków, jest z pewnością tak samo szalone jak dla matematyka twierdzenie, że 2! = 2, ponieważ druga 2 jest wielka, pogrubiona lub kursywą.
Ekkehard.Horner

5
Problem polega na tym, że C myli pojęcie „char” (tj. Część ciągu tekstowego) i „bajt” (tj (u)int_least8_t.). Sygnalizacja ma idealny sens dla małych liczb całkowitych, ale nie ma żadnego sensu dla postaci.
dan04,

@ dan04: Zgadzam się, chciałbym, żeby miały różne typy małych liczb całkowitych (podpisanych i niepodpisanych), bajtów i znaków. Kiedy wyjaśniasz początkującym, że aby manipulować surową pamięcią, muszą rzucić na char*... jak C-String, są naprawdę zdezorientowani.
Matthieu M.

C # got to prawo z oddzielnymi sbyte, byteoraz chartypów.
dan04,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.