Was ist der größte Designfehler, den Sie in einer Programmiersprache gesehen haben? [geschlossen]


29

Alle Programmiersprachen haben ihre Designmängel, einfach weil keine einzige Sprache perfekt sein kann, genau wie bei den meisten (allen?) Anderen Dingen. Abgesehen davon, welcher Designfehler in einer Programmiersprache hat Sie in Ihrer Geschichte als Programmierer am meisten geärgert?

Beachten Sie, dass, wenn eine Sprache "schlecht" ist, nur weil sie nicht für eine bestimmte Sache entwickelt wurde, dies kein Designfehler ist, sondern ein Merkmal des Designs. Listen Sie daher nicht solche Belästigungen von Sprachen auf. Wenn eine Sprache nicht für das geeignet ist, wofür sie entwickelt wurde, ist das natürlich ein Fehler im Design. Implementierungsspezifische Dinge und unter der Haube Dinge zählen auch nicht.


6
Beachten Sie, dass dies für Sprachdesigner konstruktiv ist (zu vermeidende Fehler), wenn jemand fragen möchte, wie konstruktiv diese Frage ist.
Anto


1
@greyfade: Nicht wirklich, hier geht es um Fehler in der eigentlichen Sprache, bei denen es anscheinend um Dinge geht, die die Akzeptanz einer Sprache beeinträchtigen, beispielsweise eine schlechte Standardbibliothek oder nur eine schlechte Website für die Sprache. Einige Antworten listen zB schlechte Syntax auf, aber das ist kein spezifischer Designfehler
Anto

8
Größter Fehler in einer Programmiersprache? Menschen.
Joel Etherton

Wenn diese Antworten die größten Mängel sind, dann beeindrucken mich die Programmiersprachen wirklich.
Tom Hawtin - Tackline

Antworten:


42

Eines meiner größten Ärgernisse ist die Art und Weise, wie switchFälle in C-abgeleiteten Sprachen standardmäßig auf den nächsten Fall übergehen, wenn Sie die Verwendung vergessen break. Ich verstehe, dass dies bei Code auf sehr niedriger Ebene (z. B. Duff's Device ) nützlich ist , aber normalerweise für Code auf Anwendungsebene ungeeignet ist und eine häufige Quelle für Codierungsfehler darstellt.

Ich erinnere mich, dass ich ungefähr 1995, als ich zum ersten Mal über die Details von Java las, switchsehr enttäuscht war, dass sie das Standard-Durchfallverhalten beibehalten hatten , als ich zum Teil über die Aussage kam. Dies macht nur switcheine gotomit einem anderen Namen verherrlichte .


3
@Christopher Mahan: switchmuss nicht so funktionieren. Zum Beispiel hat Adas case / when-Anweisung (entspricht switch / case) kein Fall-through-Verhalten.
Greg Hewgill

2
@Greg: switch-ähnliche Anweisungen in Sprachen, die nicht mit C zusammenhängen, müssen nicht so funktionieren. Aber wenn Sie C-Stil Steuerfluss verwenden ( {... }, for (i = 0; i < N; ++i), return, etc.), wird die Sprache Inferenz Menschen erwarten machen switchwie C zu arbeiten, und es Ada / Pascal / BASIC-ähnliche Semantik geben würde verwirrt Menschen haben. C # erfordert breakin switchAnweisungen aus dem gleichen Grund, macht es jedoch weniger fehleranfällig, indem es das stille Durchfallen verbietet. (Aber ich wünschte, Sie könnten fall;anstelle der hässlichen schreiben goto case.)
Dan04

4
dann schreibe nicht switch, schreibe if () else. Der Grund, über den Sie sich beschweren, ist, was das Umschalten besser macht: Es ist keine wahr / falsch-Bedingung, es ist eine numerische Bedingung, und das macht es anders. Sie können aber auch Ihre eigene Schalterfunktion schreiben.
jokoon

9
-1 Ich halte es für einen Vorteil, das Herunterfallen zuzulassen, es besteht keine andere Gefahr als Dummheit, aber es gewährt zusätzliche Funktionen.
Orbling

11
Das Problem ist nicht, switch dass das Durchfallen möglich ist. Es ist so, dass die meisten Verwendungen von Fallthrough nicht beabsichtigt sind.
Dan04

41

Ich habe die Verwendung =für Aufgaben und ==für Gleichheitstests in C-abgeleiteten Sprachen nie wirklich gemocht . Die Gefahr von Verwechslungen und Fehlern ist zu groß. Und fang mich nicht mal mit ===Javascript an.

Besser wäre es gewesen, sie :=zu beauftragen und =auf Gleichheit zu prüfen. Die Semantik hätte genauso aussehen können wie heute, wo Zuweisung ein Ausdruck ist, der auch einen Wert hervorbringt.


3
@ Nemanja Trifunovic: Ich dachte ursprünglich an diesen Vorschlag, aber es hat eine unglückliche Mehrdeutigkeit in C mit weniger als einem Vergleich gegen eine negative Zahl (d. H. x<-5). C-Programmierer würden diese Art von erforderlichen Leerzeichen nicht tolerieren :)
Greg Hewgill

7
@Greg: Ich würde es vorziehen :=und ==weil es zu leicht wäre, das zu vergessen :und nicht benachrichtigt zu werden, wie es schon der Fall ist (wenn auch rückgängig gemacht), wenn du ein =Heute vergisst . Ich bin dankbar für Compiler-Warnungen zu diesem Thema ...
Matthieu M.

13
Bei fast allen Tastaturen, die ich jemals verwendet habe, muss bei der Eingabe von ": =" die Umschalttaste geändert werden. Bei dem, den ich jetzt verwende, ist ':' Großbuchstabe und '=' Kleinbuchstabe, und ich habe das umgekehrt. Ich gebe viele Aufgaben ein und brauche diese Art von Tippproblemen nicht.
David Thornley

14
@ David Thornley: Code wird viel öfter gelesen als geschrieben. Ich kaufe keine Argumente über "Tippprobleme".
Greg Hewgill

8
@ Greg Hewgill: Sicher, es wird öfter gelesen als geschrieben. Das Problem zwischen =und ==liegt jedoch nicht im Lesen, da es sich um unterschiedliche Symbole handelt. Es ist schriftlich und stellt sicher, dass Sie das richtige haben.
David Thornley

29

Die Wahl von +in Javascript sowohl für das Hinzufügen als auch für das Verketten von Zeichenfolgen war ein schrecklicher Fehler. Da Werte nicht typisiert sind, führt dies zu byzantinischen Regeln, die +abhängig vom genauen Inhalt jedes Operanden bestimmen, ob sie hinzugefügt oder verkettet werden.

Am Anfang wäre es einfach gewesen, einen völlig neuen Operator einzuführen, beispielsweise $für die Verkettung von Zeichenfolgen.


13
@Barry: Nicht wirklich. +Sinnvoll als String-Verkettungsoperator in einer stark typisierten Sprache. Das Problem ist, dass Javascript es verwendet, aber nicht stark typisiert ist.
Mason Wheeler

13
@Mason: +ist für die Verkettung nicht sinnvoll, da die Verkettung definitiv nicht kommutativ ist. Für mich ist es ein Missbrauch.
Matthieu M.

12
@Matthieu: Ähm ... warum ist das wichtig? Verkettung ist nicht kommutativ (wie Addition), aber die Addition von zwei Strings ist unsinnig, so dass niemand so darüber denkt. Sie erfinden ein Problem, bei dem keines existiert.
Mason Wheeler

4
Wechseln Sie einfach zu C ++ und fügen Sie dem Operator Ihrer Wahl
Newtopian

8
@Matthieu: Kommutativität ist hier nicht das Problem. Wenn JS eine Matrix-Klasse hätte, würden Sie es für einen Missbrauch halten, einen *Operator zu haben ?
Dan04

24

Ich finde Javascript standardmäßig global zu einem Hauptproblem und häufig zu einer Fehlerquelle, wenn Sie kein JSLint oder ähnliches verwenden


2
Standard auf global? Ich bin froh, dass ich JS dann nicht benutze ...
Anto

5
Eigentlich ist es eine sehr schöne Sprache mit ein paar schlechten Designwahlen. Dies ist die Hauptvariable. Wenn Sie keinen Gültigkeitsbereich für eine Variable festlegen, wird sie als globaler Gültigkeitsbereich festgelegt. Das Gute daran ist, dass Sie mit Doug Crockfords Jslint-Programm diesen Fehler und eine Menge mehr abfangen können.
Zachary K

1
Verwenden varSie einfach, wann immer Sie eine Variable deklarieren, und Sie können loslegen. Und sag mir nicht, dass es zu viel Tipperei ist, weil Java dich zwingt, alle Typen zweimal zu deklarieren, und niemand sich darüber beschwert, dass es eine beschissene Designwahl ist.
Davidk01

3
@ davidk01: Die Leute beschweren sich darüber. In ähnlicher Weise haben sich die Leute darüber beschwert, dass std::map<KEY, VALUE>::const_iteratorin C ++ Variablen deklariert werden müssen auto, die zu dieser Sprache hinzugefügt werden.
Dan04

1
Die "use strict"in es5 hinzugefügte Direktive verwandelt nicht deklarierte Referenzen in einen Fehler.
Sean McMillan

22

Der Präprozessor in C und C ++ ist ein gewaltiger Kludge, der Abstraktionen erzeugt, die wie Siebe auslaufen, Spaghetti-Code über Rattennester von #ifdefAnweisungen fördert und fürchterlich unlesbare ALL_CAPSNamen benötigt, um seine Einschränkungen zu umgehen. Die Wurzel dieser Probleme liegt darin, dass sie eher auf der Textebene als auf der syntaktischen oder semantischen Ebene ablaufen. Es sollte für seine verschiedenen Anwendungsfälle durch echte Sprachfunktionen ersetzt worden sein. Hier einige Beispiele, obwohl einige davon zugegebenermaßen in C ++, C99 oder inoffiziellen, aber de facto Standarderweiterungen gelöst sind :

  • #include sollte durch ein echtes Modulsystem ersetzt worden sein.

  • Inline-Funktionen und Vorlagen / Generika könnten die meisten Anwendungsfälle für Funktionsaufrufe ersetzen.

  • Zum Deklarieren solcher Konstanten könnte eine Art Manifest- / Kompilierzeitkonstantenfunktion verwendet werden. Ds Erweiterungen von enum funktionieren hier hervorragend.

  • Echte Makros auf Syntaxbaumebene könnten viele verschiedene Anwendungsfälle lösen.

  • String-Mixins könnten für den Anwendungsfall der Code-Injection verwendet werden.

  • static ifoder versionAnweisungen können zur bedingten Kompilierung verwendet werden.


2
@dsimcha: Ich stimme dem #includeProblem zu, aber das Modulsystem wurde erfunden ... danach! Und C und C ++ streben ein Maximum an Abwärtskompatibilität an: /
Matthieu M.

@Matthieu: Ja, Modulsysteme wurden nach dem Motto erfunden, aber wir sprechen hier jedenfalls vom Nachhinein.
dsimcha

3
Ich stimme zu, dass dies eine massive Belastung für verschiedene Körperteile darstellt, aber das Mehrfachdurchlauf-Design hat den Vorteil der Einfachheit: Ein C-Compiler muss nicht viel über den Kontext der Operation wissen, bevor er einen Teil des C-Codes erfolgreich kompilieren kann . Dies kann nur dann als Entwurfsfehler gewertet werden, wenn Sie nachweisen können, dass die Kosten für die Verwendung eines hypothetischen Modulsystems innerhalb der C-Sprache selbst (z. B. C ++ - ähnliche Klassen) immer niedriger oder vergleichbar mit dem derzeitigen CPP-basierten #includeHacking sind.
Reinierpost

Genau. Einige Leute halten die Vorverarbeitung jedoch für eine gute Sache und beklagen, dass sie in (beispielsweise) Java nicht unterstützt wird.
Stephen C

5
@Stephen: Ich stimme zu, dass Java mit einem Präprozessor möglicherweise besser ist als Java ohne, aber nur, weil Java nicht über mehrere der "echten" Funktionen verfügt, die zum Ersetzen des Präprozessors erforderlich sind. In Sprachen wie D, die solche Funktionen enthalten, und Python, das durch seine Dynamik auf andere Weise flexibel wird, vermisse ich es kein bisschen.
dsimcha

21

Man könnte Hunderte von Fehlern in Hunderten von Sprachen auflisten, aber IMO ist dies aus Sicht der Sprachgestaltung keine nützliche Übung.

Warum?

Denn etwas, das in einer Sprache ein Fehler wäre, wäre in einer anderen Sprache kein Fehler. Zum Beispiel:

  • Wenn Sie C zu einer verwalteten Sprache (dh zu einer Sprache mit Speicherbereinigung) machen oder die primitiven Typen einschränken, würde dies seine Nützlichkeit als semi-portable Low-Level-Sprache einschränken.
  • Das Hinzufügen einer Speicherverwaltung im C-Stil zu Java (um beispielsweise Leistungsprobleme zu beheben) würde das Problem beheben.

Es gibt Lektionen zu lernen, aber die Lektionen sind selten eindeutig, und um sie zu verstehen, muss man die technischen Kompromisse und den historischen Kontext verstehen. (Zum Beispiel ist die umständliche Java-Implementierung von Generika die Folge einer übergeordneten Geschäftsanforderung zur Aufrechterhaltung der Abwärtskompatibilität.)

IMO, wenn Sie eine neue Sprache über die Gestaltung ernst meinen, müssen Sie tatsächlich nutzen ein breites Spektrum an vorhandenen Sprachen (und historische Sprachen zu studieren) ... und Ihre eigene Meinung zu bilden , was die Fehler sind. Und Sie müssen bedenken, dass jede dieser Sprachen in einem bestimmten historischen Kontext entworfen wurde, um ein bestimmtes Bedürfnis zu befriedigen.

Wenn allgemeine Lektionen zu lernen sind, befinden sie sich auf der "Meta" -Ebene:

  • Sie können keine Programmiersprache entwerfen, die für alle Zwecke geeignet ist.
  • Sie können es nicht vermeiden, Fehler zu machen, besonders wenn Sie von hinten betrachtet werden.
  • Viele Fehler sind schmerzhaft zu korrigieren ... für Benutzer Ihrer Sprache.
  • Sie müssen den Hintergrund und die Fähigkeiten Ihrer Zielgruppe berücksichtigen. dh vorhandene Programmierer.
  • Sie können nicht allen gefallen.

9
-1 - Programmiersprachen folgen Designzielen. Ein Merkmal einer Sprache, das diesen Zielen entgegenwirkt, ist ein Konstruktionsfehler, es sei denn, es ist ein notwendiger Kompromiss für eines der anderen Ziele. Nicht viele Sprachen werden mit der Absicht gemacht, alle zufriedenzustellen, aber alle Sprachen sollten versuchen, die Menschen zufriedenzustellen, die sie zuerst befriedigen wollen. Diese Art von postmodernistischer politischer Korrektheit behindert die Programmiersprachenforschung und -entwicklung.
Rei Miyasaka

Mein Punkt ist, dass es schwierig ist, Lektionen zu lernen, ohne die Entwurfsziele zu berücksichtigen.
Stephen C

1
Mir scheint, dass das OP Ihre Antwort bereits im zweiten Absatz der Frage berücksichtigt hat.
Aidan Cully

20

C und C ++ : Alle Integer-Typen, die nichts bedeuten .

Besonders char. Ist es Text oder ist es eine winzige Ganzzahl? Handelt es sich bei dem Text um ein "ANSI" -Zeichen oder eine UTF-8-Code-Einheit? Wenn es sich um eine Ganzzahl handelt, ist sie signiert oder nicht signiert?

int sollte die "native" -große Ganzzahl sein, auf 64-Bit-Systemen ist dies jedoch nicht der Fall.

longkann oder kann nicht größer sein als int. Es kann oder kann nicht die Größe eines Zeigers sein. Es ist so ziemlich eine willkürliche Entscheidung der Compiler-Autoren, ob es sich um 32-Bit oder 64-Bit handelt.

Auf jeden Fall eine Sprache der 1970er Jahre. Vor Unicode. Vor 64-Bit-Computern.


10
C wurde nicht als Standardsprache entwickelt, daher kann es kein Designfehler sein. Es wurde entwickelt, um eine CPU als portablen Assembler zu modellieren, wobei CPU-spezifischer Assembler-Code vermieden wird. Es wurde jedoch in Java behoben.

7
Ich denke, das größere Problem sind neuere Sprachen, die weiterhin dieselben bedeutungslosen Begriffe verwenden, obwohl die Geschichte uns gezeigt hat, dass es eine schreckliche Idee ist. Zumindest haben die C-Typen ihren Fehler bemerkt und Standard-Int-Typen erstellt.
Mark H

5
Ein char ist keine utf-8-Einheit. Ein utf-8-Zeichen kann mehr als 8 Bits zum Speichern benötigen. C ist keine Sprache der 1970er Jahre, ich benutze sie jetzt (freiwillig) für ein Projekt.
Dan_waterworth

4
C ist kaum mehr als eine Abstraktion auf hoher Ebene des PDP-11-Prozessors. Beispielsweise wurde die Inkrementierung vor und nach dem Start direkt vom PDP-11 unterstützt.
Bit-Twiddler

5
Dies ist eine furchtbar falsche Antwort. Zunächst einmal sind C und C ++ nicht austauschbar. Zweitens definiert die Sprachspezifikation klar, was ein Zeichen ist - Ein als Typ char deklariertes Objekt ist groß genug, um ein beliebiges Mitglied des grundlegenden Ausführungszeichensatzes zu speichern. . Drittens ist C keine "Sprache der 70er Jahre", sondern eine Sprache, die in der Nähe der Hardware lebt und wahrscheinlich die Sprache ist, die es letztendlich ermöglicht, dass all Ihre Abstraktionen auf hoher Ebene für eine CPU tatsächlich Sinn ergeben. Sie kommen als eine Person heraus, die nur hochqualifizierte Sprachen beherrscht und keine Ahnung davon hat, wie die Dinge tatsächlich funktionieren. -1
Ed S.

18

null.

Sein Erfinder Tony Hoare nennt es den "Milliarden-Dollar-Fehler" .

Es wurde in den 60er Jahren in ALGOL eingeführt und ist in den meisten heute gebräuchlichen Programmiersprachen verfügbar.

Die bessere Alternative, die in Sprachen wie OCaml und Haskell verwendet wird, ist das Vielleicht . Die allgemeine Idee ist, dass Objektreferenzen nicht null / leer / nicht vorhanden sein können, es sei denn, es gibt einen expliziten Hinweis darauf, dass dies der Fall ist.

(Obwohl Tony in seiner Bescheidenheit großartig ist, denke ich, dass fast jeder den gleichen Fehler gemacht hätte, und er war einfach der Erste.)


Nicht einverstanden, auch mit seinem Erfinder !!! null ist der leere Wert für den Zeiger- / Referenzdatentyp. Zeichenketten haben leere Zeichenketten, Mengen haben leere Mengen (Pascal empty set = []), Ganzzahlen haben 0. Die meisten Programmiersprachen, die null / nil / whatever verwenden, können bei richtiger Zuweisung einer Variablen einen Null-Fehler verhindern.
Umlcat

4
@ user14579: Jede Sprache, die eine beliebige Menge oder Zeichenfolge oder ein Array unterstützt, hat {}, aber dies ist immer noch semantisch angemessen und stürzt nicht ab, es sei denn, Sie haben bereits etwas, das möglicherweise einen Array-Begrenzungsfehler verursachen könnte - aber das ist ein anderes Problem. Sie können eine leere Zeichenfolge so verarbeiten, dass alle Zeichen in Großbuchstaben geschrieben werden, was zu einer leeren Zeichenfolge führt. Sie versuchen dasselbe mit einer Null-Zeichenfolge und ohne angemessene Überlegung stürzt sie ab. Das Problem ist, dass diese richtige Überlegung mühsam ist, oft vergessen wird und es schwierig macht, Funktionen mit einem Ausdruck (dh Lambdas) zu schreiben.
Rei Miyasaka

1
Ich verdiene jedes Mal Geld, wenn ich null tippe ... oh, richtig, jemand verliert jedes Mal Geld, wenn ich null tippe. Außer diesmal.
Kevpie

3
@umlcat - Wenn Sie Sprachen mit Mustererkennung wie Ocaml, Haskell und F # haben, verwenden Sie das Symbol Vielleicht x | Kein Muster verhindert, dass Sie beim Kompilieren den Null-Fall vergessen. In Sprachen, in denen null die festgelegte Redewendung ist, kann keine Menge von Tricks während der Kompilierung einen Fehler erkennen. Da Sie explizit festlegen müssen, dass der Null-Fall in Sprachen mit der "Vielleicht" - und "Einige" -Monade nicht behandelt wird, haben sie einen ernsthaften Vorteil gegenüber dem "Null" -Ansatz.
JasonTrue

1
@Jason - Ich stelle mir gerne maybeein Null-Opt-In vor, während die Null-Ausnahme ein Opt-Out ist. Natürlich gibt es auch einiges über den Unterschied zwischen Laufzeitfehlern und Kompilierungsfehlern zu sagen, aber allein die Tatsache, dass null im Grunde genommen das Verhalten beeinflusst, ist an sich schon bemerkenswert.
Rei Miyasaka

14

Ich habe das Gefühl, dass die Leute, die PHP entwickelt haben, keine normale Tastatur und nicht einmal eine Colemak-Tastatur verwenden, weil sie hätten erkennen müssen, was sie tun.

Ich bin ein PHP-Entwickler. PHP zu schreiben macht keinen Spaß.

Who::in::their::right::mind::would::do::this()? Der ::Bediener muss die Umschalttaste gedrückt halten und dann zwei Tasten drücken. Was für eine Energieverschwendung.

Obwohl-> das-> ist-> nicht-> viel-> besser. Dies erfordert auch drei Tastendrücke, wobei die Umschaltung zwischen den beiden Symbolen erfolgt.

$last = $we.$have.$the.$dumb.'$'.$character. Das Dollarzeichen wird enorm oft verwendet und erfordert, dass die Auszeichnung bis ganz oben auf der Tastatur reicht und die Umschalttaste gedrückt wird.

Warum konnten sie PHP nicht für die Verwendung von Schlüsseln entwickeln, die viel schneller zu tippen sind? Warum konnte we.do.this()oder musste vars nicht mit einer Taste beginnen, die nur einen einzigen Tastendruck erfordert - oder überhaupt nicht (JavaScript) und nur alle vars vordefinieren (wie ich es ohnehin für E_STRICT tun muss)!

Ich bin keine langsame Schreibkraft - aber dies ist nur eine lahme Wahl für das Design.


Perl teilt diesen Schmerz.
Daenyth

2
C ++ und aus irgendeinem unerklärlichen Grund auch PowerShell.
Rei Miyasaka

2
Verwenden Sie einen leistungsstärkeren Editor und definieren Sie Ihre eigenen Schlüsselsequenzen für diese Operatoren.
Kevin Cline

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

1
Vielleicht verwenden sie keine QWERTY-Tastaturen. $ und: Die Umschalttaste muss nicht auf allen freien Tastaturen gedrückt werden.
Arkh

13

Die Verwendung von Desktop-inspirierten Formularen innerhalb von asp.net .

Es fühlte sich immer unangenehm an und störte die Art und Weise, wie das Web tatsächlich funktioniert. Zum Glück leidet asp.net-mvc nicht in der gleichen Weise, obwohl Ruby usw. für diese Inspiration zu verdanken ist.


18
Ist das nicht eine Bibliothekssache?
Nikie

@nikie das ist ein guter Punkt;)
Taube

1
@nikie Tatsächlich ist der XML-basierte ASPX-Code eine Sprache, sodass Sie diese für die Arbeit verdrehen können. : D
CodexArcanum

2
Das eigentliche Problem mit ASP.NET ist meines Erachtens, wie schwer es ist, die Details des Webs vor dem Programmierer zu verbergen. In ASP.NET sind tatsächlich einige wirklich nützliche Dinge im Gange, aber Sie müssen so hart kämpfen und so tief graben, um darauf zuzugreifen.
CodexArcanum

1
Andererseits gibt es Tausende und Abertausende von einfachen und erfolgreichen Datenerfassungs-Apps, die mit der "klassischen" Desktop-App zusammengestellt wurden. Das einzig schlechte war, dass bis MVC die einzige Microsoft-Option die Windows-Formulare waren.
ElGringoGrande

13

Für mich ist es das absolute Fehlen von Namens- und Argumentierungskonventionen in der Standardbibliothek von PHP .

Obwohl JASS ‚s Notwendigkeit zunichte machen Referenzen nach dem referenzierte Objekt wurde freigegeben / entfernt (oder die Referenz würde und mehrere Bytes Speicher Leck würde verloren) ist ernster, aber da JASS einzige Zweck Sprache ist, ist es nicht so kritisch.


9
Das Fehlen von Konventionen in PHPs stdlib ist wohl kein Fehler im Sprachdesign .

3
@delnan: Das Fehlen von Konventionen ist darauf zurückzuführen, wie PHP entworfen wurde, und hat daher viel mit dem Sprachdesign zu tun. Auch ist mir nicht klar, dass es einen klaren Unterschied zwischen Bibliotheken und Sprache gibt. Insbesondere Lisp hat eine stolze Tradition darin, eine Sprache über eine andere zu schreiben.
btilly

1
Das wirklich Bemerkenswerte an JASS war, dass es Referenzzählungen an den Griffen hatte, diese aber nicht aufräumte, es sei denn, sie wurden manuell zerstört (und die grafische Benutzeroberfläche schuf Funktionen, die überall Speicher verloren haben)!
Craig Gidney

13

Der größte Designfehler, dem ich gegenüberstehe, ist, dass Python nicht wie Python 3.x entworfen wurde.


1
Nun, nicht einmal Guido kann alles auf einmal richtig machen ...

5
@delnan, oh ich weiß, und Python <3 ist immer noch eine erstaunlich gute Sprache, aber es ist ein wenig ärgerlich, eine bessere Sprache in Form von Python 3.x zu haben, die ich nicht verwenden kann, weil sie alle Module dieser Sprache kaputt macht Ich brauche.
Dan_waterworth

Setzen Sie Ihre Lobby für Python 3.x-Module fort! In der Zwischenzeit werde ich in 2.5.4 weiter schreiben. Dank SO werde ich tatsächlich daran erinnert, dass 3.x am Leben und in Ordnung ist.
Kevpie

@kevpie Erstens Lobbying, um Python mit einer bedingten Kompilierung zu versehen, um den Übergang für Bibliotheksverwalter zu erleichtern. 2to3 ist auf lange Sicht keine wartbare Lösung.
Evan Plaice

12

Arrayzerfall in C und folglich C ++.


Ich wünsche mir auch eine gute Array-Unterstützung. In C ++ können Sie Zerfall verhindern, indem Sie Abscons-Syntax und -Vorlagen verwenden ... aber es ist eher ein Hack: /
Matthieu M.

1
Beachten Sie, dass dies der Grund ist, dass C ++ getrennt haben muss deleteund delete[]Betreiber.
Dan04

Sie können ein Array jederzeit in eine Struktur einfügen und es nach Wert weitergeben lassen, wenn Sie möchten. Dies ist jedoch in der Regel umständlicher als das ursprüngliche Problem. In C ++ können Sie normalerweise die Verwendung von Arrays vermeiden.
David Thornley

2
Zumindest im C-Fall ist das Argument gegen die ordnungsgemäße Unterstützung von Arrays "Überprüfung der Array-Grenzen ist teuer", insbesondere angesichts der Funktionsweise der C-Zeiger-Arithmetik.
Stephen C

@Stephen C: Was hat die Überprüfung der Array-Grenzen mit dem Array-Zerfall zu tun?
Nemanja Trifunovic

11

Primitive Typen in Java.

Sie brechen das Prinzip, dass alles ein Nachkomme von ist java.lang.Object, was aus theoretischer Sicht zu einer zusätzlichen Komplexität der Sprachspezifikation führt, und machen den Gebrauch von Sammlungen aus praktischer Sicht äußerst mühsam.

Autoboxing hat dazu beigetragen, die praktischen Nachteile zu beseitigen, jedoch auf Kosten der noch komplizierteren Spezifikation und der Einführung einer großen Fettbananenschale: Jetzt können Sie eine Nullzeigerausnahme von einer einfachen Rechenoperation erhalten.


Wenn Sie primitive Typen entfernen, würde dies zu schrecklichen Leistungsproblemen führen. Und Autoboxing kann ziemlich leicht durcheinander gebracht werden, so dass es nichts verbessert.
Deadalnix

Zu dieser Zeit war dies eine vernünftige Entscheidung der Java-Designer. Die Leistungssteigerungen bei den in den 90er Jahren verfügbaren Maschinen / VMs überwogen die konzeptionellen Vorteile der Vereinheitlichung aller Funktionen rund um java.lang.Object.
mikera

10

Ich kenne Perl am besten, also werde ich mich darum kümmern.

Perl hat viele Ideen ausprobiert. Einige waren gut. Einige waren schlecht. Einige waren original und aus gutem Grund nicht weit verbreitet.

Eine davon ist die Idee des Kontexts - jeder Funktionsaufruf findet in einem Listen- oder Skalarkontext statt und kann in jedem Kontext ganz andere Dinge tun. Wie ich unter http://use.perl.org/~btilly/journal/36756 ausgeführt habe, erschwert dies jede API und führt häufig zu subtilen Designproblemen in Perl-Code.

Das nächste ist die Idee, Syntax und Datentypen so vollständig zu verknüpfen. Dies führte zur Erfindung der Bindung, damit sich Objekte als andere Datentypen tarnen können. (Sie können den gleichen Effekt auch mit Überladung erzielen, in Perl ist jedoch das Binden der üblichere Ansatz.)

Ein weiterer häufiger Fehler, den viele Sprachen begehen, besteht darin, zunächst dynamisches Scoping und nicht lexikalisches anzubieten. Es ist schwer, diese Designentscheidung später wieder rückgängig zu machen, und dies führt zu lang anhaltenden Warzen. Die klassische Beschreibung dieser Warzen in Perl lautet http://perl.plover.com/FAQs/Namespaces.html . Beachten Sie, dass dies geschrieben wurde, bevor Perl ourVariablen und staticVariablen hinzufügte .

Die Leute sind sich zu Recht nicht einig über statisches oder dynamisches Tippen. Ich persönlich mag dynamisches Tippen. Es ist jedoch wichtig, eine ausreichende Struktur zu haben, damit Tippfehler abgefangen werden können. Perl 5 leistet gute Arbeit mit strict. Aber Perl 1-4 hat das falsch verstanden. Einige andere Sprachen haben Flusenprüfer, die genau das Gleiche tun wie strenge. Solange Sie sich mit der Durchsetzung von Flusenprüfungen auskennen, ist dies akzeptabel.

Wenn Sie mehr schlechte Ideen suchen (viele von ihnen), lernen Sie PHP und studieren Sie seine Geschichte. Mein Lieblingsfehler in der Vergangenheit (der vor langer Zeit behoben wurde, weil er zu so vielen Sicherheitslücken führte) bestand darin, dass jeder durch Übergabe von Formularparametern eine Variable festlegen konnte. Das ist aber alles andere als der einzige Fehler.


5
Ja, Perl hat eine Menge Fehler, weil die Leute, die es gebaut haben, neue Ideen ausprobiert haben, und wenn Sie das tun, verstehen Sie diese oft falsch. (Perl hat auch einige sehr gute Sachen und ist der Standard für Regexps, den alle anderen kopiert zu haben scheinen)
Zachary K

@ Zachary-K: Absolut einverstanden. Und ich habe versucht, dies zu verdeutlichen, bevor ich anfing, Probleme zu lösen.
btilly

4
Lisps waren ursprünglich dynamisch und wurden im Laufe der Zeit in lexikalisch umgewandelt (zumindest in Scheme und Common Lisp). Es ist nicht unmöglich, sich zu ändern.
David Thornley

4
@ David-Dornley: Es ist unmöglich, es sei denn Sie Abwärtskompatibilität irgendwo opfern. Das Schema war immer lexikalisch. Common Lisp war seit seiner Standardisierung lexikalisch geregelt, aber verschiedene Lisp-Gemeinschaften hatten Schwierigkeiten, es zu übernehmen. Und Emacs Lisp verwendet immer noch dynamisches Scoping, obwohl es schon lange den Wunsch gibt, es zu ändern.
btilly

1
Übrigens, viele Dinge, für die Perl nicht beliebt ist, wurden nicht in Perl erfunden, sondern stammen aus anderen Sprachen, hauptsächlich der Bourne-Shell.
Reinierpost

10

Mehrdeutigkeit von JavaScripts für Codeblöcke und Objektliterale.

  {a:b}

könnte ein Codeblock sein, bei dem aes sich um eine Bezeichnung und beinen Ausdruck handelt; oder es könnte ein Objekt mit einem Attribut definieren, adas den Wert hatb


Mir gefällt das über JavaScript. Die Einfachheit der Sprachstruktur ist nett und der Zweck sollte offensichtlich sein, wenn der Entwickler weiß, was er tut.
Xeoncross

2
Xeoncross: Ich mag im Allgemeinen keine Mehrdeutigkeiten. In diesem Fall ist es für den Entwickler offensichtlich, aber eval () benötigt zusätzliche Klammern.
user281377

2
@ammoQ: Es ist offensichtlich? Was ist es dann? Ein Objekt oder ein Codeblock?
Konfigurator

Konfigurator: Offensichtlich ein Objekt. Keine vernünftige Person würde ein Etikett namens verwenden a.
user281377

10

Ich gehe zurück zu FORTRAN und der Unempfindlichkeit gegenüber Leerzeichen.

Es durchdrang die Spezifikation. Die ENDKarte musste als eine Karte mit einem 'E', einem 'N' und einem 'D' in dieser Reihenfolge in den Spalten 7 bis 72 definiert werden und keine anderen Nicht-Leerzeichen anstelle einer Karte mit "ENDE" in der richtigen Reihenfolge Spalten und sonst nichts.

Dies führte zu einer leichten syntaktischen Verwirrung. DO 100 I = 1, 10war eine Schleifensteuerungsanweisung, während DO 100 I = 1. 10es sich um eine Anweisung handelte, die einer aufgerufenen Variablen den Wert 1.1 zuweist DO10I. (Die Tatsache, dass Variablen ohne Deklaration erstellt werden konnten, deren Typ von ihrem Anfangsbuchstaben abhängt, trug dazu bei.) Im Gegensatz zu anderen Sprachen gab es keine Möglichkeit, Leerzeichen zum Trennen von Token zu verwenden, um eine Disambiguierung zu ermöglichen.

Es erlaubte auch anderen Leuten, wirklich verwirrenden Code zu schreiben. Es gibt Gründe, warum dieses Feature von FORTRAN nie wieder kopiert wurde.


1
In einer Sprache, in der Sie Literale neu definieren können, ist dies das schlechteste Beispiel - ich meine, es hat nur einen winzigen kleinen Raumflugkörper zum Absturz gebracht
Martin Beckett

Schon früh konnte man DAMNATION anstelle von DIMENSION schreiben, und es würde funktionieren.
Mike Dunlavey

Es wird immer noch von Leuten außerhalb von CS unterrichtet. Ich muss mich noch mit denen auseinandersetzen, die a) gegen Erklärungen kämpfen, b) gegen Leerzeichen kämpfen, c) wie "Fortsetzungszeilen", d) Namen mit 6 Zeichen verwenden oder 4, d) ratlos sind, wenn sie sehen (test ? a : b), e) darauf bestehen Bei Verwendung von **kann f) die Groß- / Kleinschreibung nicht behandeln. Das meiste davon war auf Tastatureingaben in den 50er Jahren zurückzuführen.
Mike Dunlavey

1
@Martin Beckett - Die Neudefinition von Literalen in FORTRAN war eher ein Compilerfehler als ein Sprachfeature. Es war sicherlich kein absichtliches Sprachmerkmal.
Stephen C

1
@oosterwal: Das habe ich sicher gemacht. Ich könnte mich irren, aber ich erinnere mich vage an die Sprachdefinition, die auf Lochkarten basiert. Sie waren damals die Haupteingabe von FORTRAN-Programmen, und die Idee einer 80-Spalten-Zeile mit den reservierten Spalten 73-80 stammt von Lochkarten.
David Thornley

9

Eines der größten Probleme bei BASIC war das Fehlen einer genau definierten Methode, um die Sprache über die frühen Umgebungen hinaus zu erweitern. Dies führte zu einer Reihe völlig inkompatibler Implementierungen (und einem nahezu irrelevanten post-facto-Versuch einer Standardisierung).

Fast jede Sprache wird von verrückten Programmierern für allgemeine Zwecke verwendet. Es ist besser, zu Beginn für den allgemeinen Gebrauch zu planen, falls die verrückte Idee auftaucht.


2
+1: Jede Sprache ohne richtige Module und Bibliotheken ist ein Fehler, der darauf wartet, passiert zu werden. Darunter litt auch COBOL, was zu eigenartigen Varianten führte, die nicht kompatibel sind.
S.Lott

8

Ich glaube an DSLs (domänenspezifische Sprachen) und eine Sache, die ich in einer Sprache schätze, ist, wenn es mir erlaubt, eine DSL darüber zu definieren.

In Lisp gibt es Makros - die meisten Leute halten das für eine gute Sache, genau wie ich.

In C und C ++ gibt es Makros - die Leute beschweren sich darüber, aber ich konnte damit DSLs definieren.

In Java wurden sie ausgelassen (und daher in C #), und das Fehlen von ihnen wurde als Tugend deklariert. Klar, Sie haben damit Intelligenz, aber für mich ist das nur ein Oeuvre . Um mein DSL zu machen, muss ich von Hand expandieren. Es ist ein Schmerz, und es lässt mich wie einen schlechten Programmierer aussehen, obwohl ich dadurch viel mehr mit Tonnen weniger Code machen kann.


4
Ich würde zustimmen, dass jede Sprache ohne anständige Makros ein riesiger, nicht behebbarer Designfehler ist. Aber was meinst du mit " sie wurden ausgelassen "? C-Präprozessor war kein anständiges Makrosystem. Java ist nicht von einer richtigen Sprache mit Makros abgeleitet.
SK-logic

1
Sie können Ihr DSL in einer externen Makroverarbeitungssprache schreiben (wie beispielsweise m4 unter einer Vielzahl von anderen).
NUR MEINE STELLUNGNAHME

4
@SK: Ich würde nicht sagen, dass der C-Präprozessor im Vergleich zu Lisp (zum Beispiel) ein anständiges Makrosystem ist. Aber im Vergleich zu nichts ist es äußerst nützlich.
Mike Dunlavey

4
@reinierpost: Ich denke an Dinge, die ich in Lisp tun könnte, wie Kontrollstrukturen wie differentielle Ausführung und Backtrack einzuführen. Dies könnte mit Lisp-Makros geschehen. In C / C ++ konnte ich mit C-Makros (und ein wenig Programmierer-Disziplin) differenzielle Ausführungen machen, aber keinen Backtrack. Mit C # kann ich beides nicht. Was ich dafür bekomme, sind Dinge wie Intellisense. BFD.
Mike Dunlavey

1
@David: So wie ich es gemacht habe, hatte ich ein Makro, mit dem ich gewöhnlichen Code umbrechen konnte, z. B. eine Liste von Anweisungen. Es würde das cdrvon der Liste nehmen und einen Lambda-Abschluss daraus bilden (dh eine Fortsetzung) und es als Argument an das carvon der Liste weitergeben. Das wurde natürlich rekursiv gemacht und würde "das Richtige tun" für Bedingungen, Schleifen und Funktionsaufrufe. Dann hat sich die "Auswahl" -Funktion in eine normale Schleife verwandelt. Nicht hübsch, aber robust. Das Problem ist, dass es sehr einfach ist, übermäßig verschachtelte Schleifen zu erstellen.
Mike Dunlavey

7

Aussagen , in jeder Sprache, die sie hat. Sie tun nichts, was Sie mit Ausdrücken nicht tun können, und hindern Sie daran, viele Dinge zu tun. Die Existenz eines ?:ternären Operators ist nur ein Beispiel dafür, dass man versuchen muss, sie zu umgehen. In JavaScript sind sie besonders ärgerlich:

// 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')

Ich bin hier verwirrt: Willst du nur eine einfachere Möglichkeit, Dinge zu tun?
TheLQ

2
Richtig. Ausdrücke für alles.
Munificent

1
Lisp funktioniert gut dafür.
David Thornley

1
@ SK-logic: Ich vermute, dass Anweisungen blind von der Maschinensprache durch FORTRAN, ALGOL und COBOL geerbt wurden.
David Thornley

1
Ich bin mir ziemlich sicher, dass die Maschinensprache der gemeinsame Vorfahr ist, und das spiegelt nur die Tatsache wider, dass moderne Computer, die auf der von Neumann-Architektur basieren, Anweisungen nacheinander ausführen und den Status ändern. Letztendlich wird es bei E / A-Vorgängen Ausdrücke geben, die keine aussagekräftigen Daten liefern, sodass Anweisungen nicht völlig unbrauchbar sind, um semantisch anzuzeigen, dass ein Teil des Codes nur Nebenwirkungen hat. Sogar Sprachen, die einen Begriff vom unitTyp (aka ()) anstelle von Anweisungen haben, müssen besonders berücksichtigt werden, um sicherzustellen, dass sie keine Warnungen auslösen oder sich auf andere Weise merkwürdig verhalten.
Rei Miyasaka

6

Für mich ist es das Designproblem, das alle Sprachen plagt, die von C abgeleitet wurden; nämlich das " sonst baumeln ". Dieses grammatikalische Problem hätte in C ++ gelöst werden müssen, wurde jedoch in Java und C # ausgeführt.


3
Eines der Hauptziele von C ++ war, vollständig abwärtskompatibel mit C zu sein. Wenn sie das semantische Verhalten drastisch verändert hätten, hätte es sich möglicherweise nicht so angefühlt wie es war (oder zumindest war dies der Gedanke zu dieser Zeit)
Ed S.

2
@Ed S. Die Beseitigung des Problems des "Dangling else" hätte jedoch dadurch erreicht werden können, dass die Grammatikproduktion <compound_statement> (auch bekannt als <block>) beseitigt und die geschweiften Klammern in die bedingten und iterativen Kontrollstrukturen aufgenommen wurden, wie sie es damals taten Die Kontrollstruktur zur Behandlung von Try / Catch-Ausnahmen wurde hinzugefügt. Es gibt keine Entschuldigung, diese grammatikalische Mehrdeutigkeit in Java und C # nicht zu korrigieren. Gegenwärtig besteht die defensive Lösung für diese grammatische Mehrdeutigkeit darin, jede Anweisung, die auf eine bedingte oder iterative Steueranweisung folgt, zu einer zusammengesetzten Anweisung zu machen.
Bit-Twiddler

1
Was meinst du damit? Dies ist kein „grammatikalisches Problem“ (es ist völlig eindeutig). Wie würden Sie es "lösen"? Ich finde die Regeln in C eigentlich befriedigend. Nur eine Python-ähnliche Syntax (= sinnvolle Einrückung) kann dieses Problem wirklich lösen. Darüber hinaus bin ich eigentlich sehr zufrieden , dass moderne Sprachen werden nicht Mandat Klammern. Ich bin damit einverstanden, dass alle C-ähnlichen Syntaxen scheiße sind, aber baumeln - sonst ist das geringste ihrer Probleme.
Konrad Rudolph

1
Fortsetzen: Ich denke, dass Pythons Verwendung einer Einrückung als Mittel zur Abgrenzung einer Anweisungsliste unglaublich seltsam ist. Diese Technik verstößt gegen das Prinzip der "Trennung von Bedenken", indem das lexikalische Scannen eng mit der Syntaxanalyse verknüpft wird. Eine kontextfreie Grammatik sollte analysiert werden können, ohne etwas über das Layout der Quelle zu wissen.
Bit-Twiddler

3
@bit-twiddler: Nein, das tut es nicht. Der Python-Lexer konvertiert nur die Leerzeichen in die entsprechenden INDENT- und DEDENT-Token. Sobald das erledigt ist, hat Python eine ziemlich konventionelle Grammatik ( docs.python.org/reference/grammar.html ).
Dan04

6

Ich denke, alle bisherigen Antworten deuten auf ein einziges Versagen vieler gängiger Sprachen hin:

Es gibt keine Möglichkeit, die Hauptsprache zu ändern, ohne die Abwärtskompatibilität zu beeinträchtigen.

Wenn dies gelöst ist, können so ziemlich alle anderen Griffe gelöst werden.

BEARBEITEN.

Dies kann in Bibliotheken durch unterschiedliche Namespaces gelöst werden, und Sie könnten sich vorstellen, für den größten Teil des Kerns einer Sprache etwas Ähnliches zu tun, obwohl dies dann bedeuten könnte, dass Sie mehrere Compiler / Interpreter unterstützen müssen.

Letztendlich glaube ich nicht, dass ich weiß, wie ich es auf eine völlig zufriedenstellende Weise lösen kann, aber das bedeutet nicht, dass es keine Lösung gibt oder dass nicht mehr getan werden kann


1
Wie würden Sie vorgehen, um dieses Problem zu lösen?
Bjarke Freund-Hansen

Ich bin nicht sicher , kann es völlig gelöst werden - offensichtlich Dinge aus der Kernsprache und in einer Standard - Bibliothek zu halten hilft so dass ich glaube , ich würde versuchen , dies zu schieben , so weit wie es gehen könnte
jk.

1
Meinen Sie mit abwärtskompatibel, dass neuere Compiler in der Lage sein sollten, alten Code zu kompilieren?
Rei Miyasaka

Ich meine, neuere Compiler sollten die Bedeutung von altem Code nicht ändern, ein Fehler beim Kompilieren wäre eine Teilmenge davon
jk.

In den meisten Fällen, in denen eine bestimmte Funktion nicht vorhanden ist oder geändert werden soll, erstellen die Benutzer eine neue Sprache, die auf der vorherigen basiert. C mit Klassen => C ++
umlcat


4

Sowohl Java als auch C # haben ärgerliche Probleme mit ihren Typsystemen, da beim Hinzufügen von Generika die Abwärtskompatibilität beibehalten werden soll. Java mag es nicht, Generika und Arrays zu mischen. In C # sind einige nützliche Signaturen nicht zulässig, da Sie keine Werttypen als Grenzen verwenden können.

Betrachten Sie das als Beispiel für Letzteres

public static T Parse <T> (Typ <T>, Zeichenfolge str) wobei T: Enum
neben oder ersetzen
öffentliches statisches Objekt Parse (Typ type, string str)
in der EnumKlasse würde erlauben
MyEnum e = Enum.Parse (typeof (MyEnum), str);
eher als die tautologische
MyEnum e = (MyEnum) Enum.Parse (typeof (MyEnum), str);

tl; dr: Denken Sie über den parametrischen Polymorphismus nach, wenn Sie mit dem Entwerfen Ihres Typsystems beginnen, nicht nachdem Sie Version 1 veröffentlicht haben.


2
Die Unfähigkeit, Typen auf Enum zu beschränken, ist in C # ärgerlich, aber Sie können es auf diese Weise MyMethod<T>(T value) where T : struct, IComparable, IFormattable, IConvertible umgehen. Aber Sie müssen immer noch auf eine Enumeration testen und es ist ein Hack. Ich denke, der größere Mangel an C # -Generika ist keine Unterstützung für höhere Arten, was die Sprache wirklich für einige coole Konzepte öffnen würde.
CodexArcanum

4

Ich habe das Gefühl, ich öffne mich für Flammen, aber ich hasse die Möglichkeit, alte Datentypen als Referenz in C ++ zu übergeben. Ich hasse es nur wenig, komplexe Typen als Referenz übergeben zu können. Wenn ich mir eine Funktion anschaue:

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

Vom aufrufenden Punkt aus kann man nicht sagen, dass bar:

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

Einige mögen argumentieren, dass so etwas einfach ein schlechtes Software-Design ist und nicht die Schuld an der Sprache hat, aber ich mag es nicht, dass die Sprache es Ihnen überhaupt erlaubt, dies zu tun. Zeiger benutzen und anrufen

bar(&a);

ist viel lesbarer.


+1 Ich stimme Ihnen nicht zu, aber ich schätze Ihre Argumentation.
Jon Purdy

@Jon Mich würde eigentlich sehr interessieren, was du denkst. Tragen Sie die Ansicht "Tadeln Sie nicht die Sprache"?
Jeff

6
@Jeff: Zum einen war der Hauptgrund, warum die Referenzsemantik in C ++ Einzug gehalten hat, die Überladung von Operatoren, für die ein einheitliches Referenzverhalten einfach Sinn macht. Noch wichtiger ist jedoch, dass C ++ vielseitig einsetzbar ist und sehr feinkörnige Funktionen bietet, auch wenn dabei ein erhebliches Risiko für Programmiererfehler besteht. Also ja, zumindest in diesem speziellen Fall, beschuldigen Sie nicht die Sprache. Ich möchte lieber Fehler machen können, als dass mir eine Sprache im Weg steht.
Jon Purdy

@ Jon war sich einig, dass es sehr seltsam wäre, einen Verweis auf alles außer PODs zu verwenden. Ich würde es vorziehen, wenn dieses Feature alternativ komplett in C ++ fehlen würde, aber wir können zustimmen, dass wir dem nicht zustimmen :). Danke für die Eingabe!
Jeff

Java scheint Zeiger nicht so sehr zu mögen wie Sie.
Mateen Ulhaq

4

ÄNDERN

Als ich COBOL lernte, war die ALTER-Anweisung immer noch Teil des Standards. Kurz gesagt, mit dieser Anweisung können Sie Prozeduraufrufe zur Laufzeit ändern.

Die Gefahr bestand darin, dass Sie diese Anweisung in einen undurchsichtigen Codeabschnitt schreiben konnten, auf den nur selten zugegriffen wurde, und das Potenzial bestand, den Ablauf des restlichen Programms vollständig zu ändern. Mit mehreren ALTER-Anweisungen könnten Sie es fast unmöglich machen, zu jedem Zeitpunkt zu wissen, was Ihr Programm tat.

Mein Universitätslehrer erklärte sehr nachdrücklich, dass er uns automatisch durchfallen würde, wenn er diese Aussage jemals in einem unserer Programme sehen würde.


Es gibt jedoch gute Anwendungsfälle - Stubbing oder Memoization. Anstatt zu schreiben v() { if (not alreadyCalculatedResult) { result = long(operation); alreadyCalculatedResult = true; } result; }, sagst duv() { result = long(operation); v = () => result; result; }
Konfigurator

4

Die schlimmste Sünde einer Programmiersprache ist nicht gut definiert. Ein Fall, an den ich mich erinnere, ist C ++, das in seinen Ursprüngen:

  1. War so schlecht definiert, dass Sie kein Programm zum Kompilieren und Ausführen anhand der folgenden Bücher oder Beispiele bekommen konnten.
  2. Sobald Sie das Programm so optimiert haben, dass es unter einem Compiler und Betriebssystem kompiliert und ausgeführt wird, müssen Sie von vorne beginnen, wenn Sie zwischen Compilern oder Plattformen gewechselt haben.

Wie ich mich erinnere, dauerte es ungefähr ein Jahrzehnt, bis C ++ so gut definiert war, dass es so professionell zuverlässig war wie C. Es sollte nie wieder vorkommen.

Etwas anderes, was ich als Sünde betrachte (sollte es eine andere Antwort sein?), Ist, mehr als einen "besten" Weg zu haben, um eine gemeinsame Aufgabe zu erledigen. Es ist der Fall von (wieder) C ++, Perl und Ruby.


1
Ich verstehe nicht, wie man Unklarheiten in einer sich entwickelnden Sprache vermeidet. Oder in einer vorgefertigten Sprache, in der der ursprüngliche Designer einige wichtige Punkte übersehen hat (wie Pascal).
David Thornley

@ David Thornley Gut definiert ist gut definiert. Trotz aller Fehler haben die meisten Programmiersprachendesigner von Anfang an alles richtig gemacht. Tools können überprüfen, ob eine Grammatik eindeutig ist, wenn sie vollständig ist (C ++ erfordert mindestens drei Grammatiken), und die Semantik sollte für Standardimplementierungen angegeben werden.
Apalala

Ich bin damit einverstanden, dass gut definierte Sprachen möglich sind, aber das wird in einer sich entwickelnden Sprache wie C ++ vor dem Standard nicht passieren. Die Alternative besteht darin, dass jede Sprache vor der Veröffentlichung sorgfältig entwickelt wird und dies nicht unbedingt der Weg ist, um die besten Sprachen zu erhalten. Ich würde sagen, dass die meisten Programmiersprachendesigner am Anfang etwas falsch machen, da das Sprachdesign extrem kompliziert ist.
David Thornley

Ich glaube, ich habe Probleme zu verstehen, was Sie mit "gut definiert" meinen. Ist Ihre Beschwerde, dass verschiedene C ++ - Compiler nicht dieselbe Sprache kompiliert haben?
Sean McMillan

3

Klassen in C ++ sind eine Art erzwungenes Entwurfsmuster in der Sprache.

Es gibt praktisch keinen Unterschied zur Laufzeit zwischen einer Struktur und einer Klasse, und es ist so verwirrend zu verstehen, was der wahre Programmiervorteil des "Versteckens von Informationen" ist, dass ich es hier platzieren möchte.

Ich werde dafür abgelehnt, aber auf jeden Fall sind C ++ - Compiler so schwer zu schreiben, dass sich diese Sprache wie ein Monster anfühlt.


2
Das Ausblenden von Informationen ist wichtig, da Sie damit implementierungsspezifische Details, die sich wahrscheinlich ändern, vor den zugänglichen Teilen der API (der "Benutzeroberfläche" der API) verbergen können, wodurch Änderungen am Programm einfacher und schmerzfreier werden.
Anto

1
Die Benutzeroberfläche der API ... nein, im Ernst, ich kaufe es nicht.
jokoon

3
Dieser Unterschied ist nicht der empörendste Teil von C ++, auch nicht in der Nähe. Der einzige Unterschied ist ein Standardzugriffsmodifikator (public für Strukturen, private für Klassen). C ++ ist eine schreckliche, monströse Sprache, aber sicherlich nicht in diesem Teil.
SK-logic

sk-logic: nun, ich könnte sagen, die horrors fangen dort an.
jokoon

2
Das Verstecken von Informationen ist gut; Diskussionen darüber gibt es überall. Das einzige herausragende Software-Buch, an das ich denken kann, dass es dagegen war, war Brooks '"The Mythical Man-Month", und er betrachtete es später als den größten Fehler im Buch. Wenn Sie die Vorteile nicht verstehen, sind Sie wirklich nicht qualifiziert, das Urteil zu fällen, das Sie fällen.
David Thornley

3

Obwohl jede Sprache ihre Fehler hat, ist keine eine Belästigung, wenn man sie erst einmal kennt. Mit Ausnahme dieses Paares:

Komplexe Syntax gepaart mit einer wortreichen API

Dies gilt insbesondere für eine Sprache wie Objective-C. Die Syntax ist nicht nur überwältigend komplex, sondern die API verwendet Funktionsnamen wie:

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

Ich bin alles dafür, explizit und eindeutig zu sein, aber das ist lächerlich. Jedes Mal, wenn ich mich mit xcode hinsetze, fühle ich mich wie ein n00b und das ist wirklich frustrierend.


Die Objective-C-Syntax ist überwiegend komplex? Hast du C ++ noch nicht gesehen? Und der eigentliche Methodenname ist da tableView:cellForRowAtIndexPath:, was meiner Meinung nach sehr aussagekräftig ist.
Rightfold

Lerne das Tippen.
21.

2
  1. signierte Zeichen in C - ein Gräuel, der erfunden wurde, um Mathematikern große Sammlungen kleiner Gegenstände zu ermöglichen
  2. Verwenden von case, um semantischen Inhalt zu transportieren - wieder für Mathematiker, die nicht sprechen müssen und nie genug Platz für ihre Formeln haben
  3. Let / Plain-Zuweisung vs. Set-Zuweisung in Basic-Dialekten - hier sind meiner Meinung nach keine Mathematiker involviert

Könnten Sie mir erklären, dass ich den Kommentar zu Ihren unterschriebenen Zeichen verloren habe?
Winston Ewert

1
Für einen Menschen ist das Konzept von (nicht) vorzeichenbehafteten Zeichen und die Notwendigkeit, dem Compiler vorzuschreiben, nicht vorzeichenbehaftete Zeichen als Standard zu verwenden, genauso verrückt wie für einen Mathematiker die Behauptung, dass 2! = 2, weil die zweite 2 groß und fett ist oder kursiv.
Ekkehard.Horner

5
Das Problem ist, dass C das Konzept von "char" (dh Teil einer Textzeichenfolge) und "byte" (dh (u)int_least8_t) verwechselt . Die Signiertheit ist für kleine ganze Zahlen vollkommen sinnvoll, für Zeichen jedoch überhaupt nicht.
Dan04

@ dan04: Ich stimme zu, ich wünschte, sie hätten verschiedene Typen für kleine Ganzzahlen (mit und ohne Vorzeichen), Byte und Zeichen. Wenn Sie Neulingen erklären, dass sie zur Manipulation des Rohspeichers in einen char*... wie einen C-String umgewandelt werden müssen, werden sie wirklich verwirrt.
Matthieu M.

C # bekam dieses Recht mit separaten sbyte, byteund charTypen.
dan04 06.03.11
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.