KISS-Prinzip beim Design von Programmiersprachen?


14

KISS ("halte es einfach, dumm" oder "halte es einfach, dumm", siehe z. B. hier ) ist ein wichtiges Prinzip in der Softwareentwicklung, obwohl es anscheinend aus dem Ingenieurwesen stammt. Zitiert aus dem Wikipedia-Artikel:

Das Prinzip lässt sich am besten anhand der Geschichte veranschaulichen, wie Johnson einem Team von Konstrukteuren eine Handvoll Werkzeuge übergibt, mit der Herausforderung, dass das von ihnen konstruierte Düsenflugzeug von einem durchschnittlichen Mechaniker auf dem Feld unter Kampfbedingungen nur mit diesen Werkzeugen repariert werden kann. Daher bezieht sich der Begriff "dumm" auf die Beziehung zwischen der Art und Weise, wie Dinge zerbrechen, und der Raffinesse, die zur Verfügung steht, um sie zu beheben.

Wenn ich dies auf den Bereich der Softwareentwicklung anwenden wollte, würde ich "Düsenflugzeug" durch "Stück Software", "durchschnittlicher Mechaniker" durch "durchschnittlicher Entwickler" und "unter Kampfbedingungen" durch "unter der erwarteten Softwareentwicklung / -wartung" ersetzen Bedingungen "(Fristen, Zeitbeschränkungen, Besprechungen / Unterbrechungen, verfügbare Tools usw.).

Es ist daher eine allgemein akzeptierte Idee, dass man versuchen sollte, ein Stück Software einfach (oder einfach dumm , falls Sie das Komma weglassen) zu halten, damit es später einfach ist, daran zu arbeiten.

Aber kann das KISS-Prinzip auch auf die Gestaltung von Programmiersprachen angewendet werden? Kennen Sie Programmiersprachen, die speziell für dieses Prinzip entwickelt wurden, um "einem durchschnittlichen Programmierer unter normalen Arbeitsbedingungen zu ermöglichen, mit geringstem kognitiven Aufwand so viel Code wie möglich zu schreiben und zu pflegen"?

Wenn Sie eine bestimmte Sprache zitieren, wäre es großartig, wenn Sie einen Link zu einem Dokument hinzufügen könnten, in dem diese Absicht von den Sprachdesignern klar zum Ausdruck gebracht wird. In jedem Fall wäre ich interessiert, mehr über die (dokumentierten) Absichten der Designer zu erfahren, als über Ihre persönliche Meinung zu einer bestimmten Programmiersprache.


4
Haben Sie die grundlegende Sprachfamilie (oder zumindest die ursprüngliche Absicht dahinter) erkundet?

4
BASIC und Pascal ... beide als Unterrichtssprachen konzipiert.
Michael Brown

1
Was meinst du mit einfach? Die meisten Sprachen sind ziemlich einfach, da sie nicht viel zu bieten haben. Nichts war weniger komplex als der Assembler. Frameworks sind oft kompliziert, aber sie sollen es ermöglichen, "mit dem geringsten kognitiven Aufwand so viel Code wie möglich zu schreiben und zu pflegen".
pdr

7
Schema (r) wurde jahrelang (Jahrzehnte?) Als Unterrichtssprache verwendet und durch Vereinfachung von LISP und Algol (und möglicherweise mehr) entwickelt. Das Buch SICP benötigt sehr viel weniger Zeit, um die Sprache selbst zu unterrichten. Auch kommen DSLs in den Sinn.
vpit3833

3
@Giorgio schau dir Haskell an. Es hat sehr und ich meine sehr wenig eingebaute Teile. Die meisten Operatoren sind Funktionen, die sich in der Hauptbibliothek befinden, für die Sprache selbst jedoch nicht erforderlich sind. Es wurde sehr viel unternommen, um alle unnötigen Teile zu entfernen
Jimmy Hoffa,

Antworten:


15

Wenn ich an Minimalismus denke, denke ich an Lisp and Go . Mit Lisp haben Sie nur Funktionen und Listen, die so einfach wie möglich sind (nun, es gibt ein bisschen mehr, aber was auch immer). Ich denke jedoch, dass der Fall Go interessanter ist.

Go wurde so konzipiert, dass es einfach ist (eine anständige Lektüre). Der Begriff, den sie verwenden, ist "Feature-Orthogonalität", was bedeutet, dass jedes Feature nur hinzugefügt werden sollte, wenn es etwas wirklich Einzigartiges bietet. Dies scheint auf die Autoren ( Russ Cox und Rob Pike) zurückzuführen zu sein ) mit Plan9 befasst haben , einer Neuinterpretation von UNIX mit dem Ziel der Einfachheit. (Wenn Sie an minimalem Design interessiert sind, ist Rob Pikes Artikel über ein einfaches Fenstersystem eine gute Lektüre.)

Hier sind einige einfache Beispiele für die Syntax:

Nur ein Schleifenkonstrukt

Eine Schleife kann folgendermaßen aussehen:

Endlosschleife

for {
}

While-Schleife

for <conditional> {
}

Traditionell für Schleife

for i := 0; i < 10; i++ {
}

Foreach-Schleife

// works for maps or arrays
for k, v := range arr {
}

Mehrzweckschalter

switch {
    // cases must be evaluate to a boolean
}

switch <value> {
}

switch t := <value>; t {
    // can use t inside
}

Mehrfachrückgabe

return val1, val2, ...
  • Entfernt die Notwendigkeit eines Wurfs (übergebe den Fehler als letzten Rückgabewert)
  • Entfernt die Notwendigkeit von out-Parametern
  • Entfernt die Notwendigkeit von Tupeln

Schnittstellen

type X interface {
    DoSomething()
    String() string
}
  • Löst ähnliche Probleme wie Generika
  • Ermöglicht die Abstraktion

Einbetten

type A struct {
    Thing string
}

type B struct {
    A // embeds A in B, so B.Thing refers to A.Thing
}
  • Behebt das gleiche Problem wie die Vererbung
  • Vermeidet Unterrichtsbedarf

Kanäle

Kann zur Implementierung von Semaphoren verwendet werden

var c = make(chan bool, 1)
c<-true // semaphore lock
<-c // semaphore free

Wird für die Nachrichtenübermittlung zwischen Threads verwendet

func produce(c chan<- bool) {
    for {
        c <- true
    }
}
func consume(c <-chan bool) {
    for {
        <-c
    }
}

var c = make(chan bool)
go produce(c)
go consume(c)

Kann zur Behandlung von asynchronen Ereignissen verwendet werden

func async() chan bool {
    var c = make(chan bool)
    go doSomethingAsync(c)
    return c
}

// wait for long async process to finish
c := async()
select {
    case _ = <-c:
}

Fazit

Ich werde nicht auf jeden Teil der Syntax eingehen, aber hoffentlich können Sie sehen, was Minimalismus bewirken kann. Die Sprache ist nicht faszinierend, weil sie eine Menge neuer Funktionen hinzufügt, sondern weil sie die besten Funktionen aus anderen Sprachen ohne zusätzliche Vorteile nutzt.

Normalerweise gibt es einen "besten" Weg, ein Problem zu lösen. Zum Beispiel beschweren sich viele Benutzer in der Mailingliste, dass sie keine Generika haben. Nach der Diskussion stellen sie fest, dass alles, was sie wollen, mit Schnittstellen gemacht werden kann. Informieren Sie sich über effektive Beispiele zur idiomatischen Syntax.

Der Vorteil von KISS-Sprachen ist, dass es möglich ist, idiomatischen Code zu schreiben, da der Codestil durch die Sprache eingeschränkt ist. In Go können Sie beispielsweise nicht so etwas schreiben:

if <condition>
    statement;

Sie müssen geschweifte Klammern verwenden:

if <condition> {
    statement;
}

Es gibt viele andere Beispiele in der Syntax, die das Lesen des Codes anderer Leute erleichtern.

Vorteile der KISS-Sprache gegenüber attraktiven Sprachen:

  • Code anderer leichter zu verstehen
  • einfacher die gesamte Sprache zu erlernen (C ++ ist dafür bekannt, dass es schwer zu verstehen ist)
  • konzentrieren Sie sich auf den Algorithmus, nicht auf die Syntax

5
Meiner bescheidenen Meinung nach ist die Syntax der traditionellen for-Schleife nicht die von KISS. Natürlich ist es jedem C-ähnlichen Programmierer vertraut, aber ich erinnere mich an das erste Mal, als ich das lernte: Ich war sehr verwirrt. BASIC ist mehr KISS: for i=1 to 10oder Python:for item in group
Mouviciel

3
@mouviciel - Ich benutze die traditionelle for-Schleife selten. Das Problem dabei for i = 1 to 10ist, ob ies jemals 10 geben wird. Dies kann sprachabhängig sein (Bash enthält 10, Python nicht). Die traditionelle for-Schleife ist universell.
Beatgammit

+1, insbesondere für die Zusammenfassung über die Vorteile des Minimalismus.
Giorgio

1
Eine Fallstudie ist interessant, da sie von ihren Kritikern nicht als KISS-Sprache angesehen wird. Tatsächlich lautet das Argument so: Eine "einfache" Sprache führt nicht zu "einfachem" Code oder einfacherem Verständnis. Manchmal muss die Komplexität größer sein (z. B. eine gute Unterstützung für Generika), damit der Code leichter zu verstehen ist.
Andres F.

13

Ich denke, das Zen von Python wird erklären, warum Python eine einfache Sprache ist, die viel besser ist als ich:

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Bearbeiten als Antwort auf @Giorgio

Wie Ihre Frage besagt,

"Kennen Sie Programmiersprachen, die speziell unter Berücksichtigung dieses Prinzips entwickelt wurden, um 'einem durchschnittlichen Programmierer unter durchschnittlichen Arbeitsbedingungen zu ermöglichen, mit geringstem kognitiven Aufwand so viel Code wie möglich zu schreiben und zu pflegen'?"

Python fällt mir sofort ein. Pythons Design ist eine direkte Antwort auf Perls Methodik, das berühmte "Es gibt mehr als eine Möglichkeit, es zu tun". Das ist zwar großartig, da Programmierer sehr einfach Code schreiben können, aber bei der Wartung hilft es nicht. Nachdem ich zuvor ein (wie ich zugeben werde) sehr schlecht geschriebenes Programm in Perl geschafft habe, schätze ich es, dass Python sowohl gute Codierungspraktiken als auch eine prägnante Sprache forciert.

Python zwingt Sie auch nicht, beim Schreiben von Programmen eine bestimmte Methode zu befolgen. Ich kann mich für einen strengen objektorientierten Programmierstil entscheiden oder ein einfaches Skript schreiben, das nacheinander ausgeführt wird. Sie müssen keine Klasse initialisieren und rufen dann die aufmain() ist sehr schön, keine Methode Sie in Java ausführen müssen. (Auch in Python auf stdout zu drucken ist wunderbar, aber das ist eher ein Nullpunkt).

Schließlich ist die "Batteries Included" -Methode, mit der eine umfangreiche Standardbibliothek in die Sprache aufgenommen wird, wunderbar. Anstatt in einem externen Repository nach Paketen zu suchen, ist das meiste, was ich benötige, bereits in der Sprache enthalten. Es ist auch schön, dieses externe Repo zu haben, aber es ist wirklich praktisch, nicht darin zu graben, um eine grundlegende Operation durchzuführen.


3
Vielen Dank für das nützliche Zitat. Ist dies die offizielle Absicht von Pythons Designern? Beachten Sie auch, dass möglicherweise nicht alle Leser Ihrer Meinung zu Python zustimmen. Daher ist es möglicherweise etwas zu stark, um zu behaupten, dass "Python eine einfache Sprache ist", eine allgemein bekannte und akzeptierte Tatsache. Wäre es möglich, es als "Python wurde mit dem Gedanken an Einfachheit entworfen" zu formulieren?
Giorgio

@ Giorgio - Es ist die Erfahrung vieler Entwickler hier, dass Python eigentlich eine einfache Sprache ist. Einfach zu lernen, einfach zu schreiben und einfach zu lesen. Über das Zitat, da Python "Batterien enthalten" ist, können Sie es direkt aus der Sprache mit import thisBefehl erhalten.
Mouviciel

1
TCL ist auch eine gute Antwort darauf und IIRC war auch eine Antwort auf die Komplexität von PERL.
jk.

@mouviciel Nachdem ich an mehreren Stellen auf erstaunlich verschlungenen Python-Spaghetti-Code gestoßen bin, glaube ich nicht mehr, dass Python hier seine Ziele erreicht. Python ist nicht besser als die meisten anderen Sprachen, wenn es um Einfachheit geht - es kann sehr gut bei versehentlicher Verschleierung sein.
Izkata

1
Python ist einfach, solange sich die Leute von den meisten __magic_functions __ () und @decorators fernhalten.
weberc2

3

Ein wesentlicher Schlüssel zur Aufrechterhaltung der "Einfachheit" besteht darin, zu erkennen, wann Komplexität erforderlich sein wird, und die Teile des Systems, die am besten damit umgehen können, zu veranlassen, dies zu tun. Eine einzige Art von Objektreferenz, die keinen Unterschied zwischen unveränderlichen Werten, veränderlichen Werten und Entitäten macht, macht Java "einfach" und beseitigt nicht die Notwendigkeit, zwischen Werten und Entitäten zu unterscheiden. Es entzieht Programmierern lediglich die Werkzeuge, um ihnen dabei zu helfen.

Wenn eine Programmiersprache oder ein Framework-Feature mehrere Anwendungsfälle unterstützen soll, sollte im Allgemeinen sichergestellt werden, dass es keine Situationen gibt, in denen unterschiedliche Verhaltensweisen in verschiedenen Anwendungsfällen angemessen wären, der Compiler dies jedoch nicht feststellen kann sie auseinander. Das Hinzufügen weiterer Typen zu einer Sprache oder einem Framework mag kompliziert erscheinen, erleichtert jedoch in vielen Fällen die Arbeit.

Betrachten Sie beispielsweise das Durcheinander von Regeln, die vorzeichenbehaftete und vorzeichenlose Typen in C umgeben. Die Komplexität dieser Regeln ergibt sich aus der Tatsache, dass in einigen Codes vorzeichenlose Ganzzahltypen zur Darstellung von Zahlen verwendet werden, während in anderen Codes Elemente eines umschließenden algebraischen Rings dargestellt werden (Insbesondere die Menge der ganzen Zahlen kongruent mod 2ⁿ). Die Typkonvertierungsregeln verhalten sich in einer Weise, die manchmal für die eine Verwendung und manchmal für die andere Verwendung geeignet ist. Wenn getrennte Umbruch- und Nicht-Umbruch-Typen verwendet werden, wird die Anzahl der Ganzzahltypen verdoppelt, die damit verbundenen Regeln könnten jedoch vereinfacht werden:

  • Jeder Nicht-Ring-Integer-Typ beliebiger Größe kann einem Ring beliebiger Größe zugewiesen werden. Ein Ring kann nur einem Ring gleicher oder kleinerer Größe zugewiesen werden .

  • Andere Operationen als Vergleichsoperatoren, die eine Ganzzahl ohne Ring und einen Ring umfassen, konvertieren die Ganzzahl implizit in den Ringtyp.

  • Ringe können explizit auf Zahlen oder größere Ringe gegossen werden. Der Wert eines Rings ohne Vorzeichen ist die kleinste nicht negative ganze Zahl, die, wenn sie zur Null des Rings addiert wird, den Ringwert ergibt. Der Wert eines vorzeichenbehafteten Rings ist die kleinste Ganzzahl, die, wenn sie zur Ringnull addiert wird, den Ringwert ergibt, wobei der negative Wert im Falle eines Gleichstands bevorzugt wird.

  • Außer wie oben erwähnt, sind Ringe auf Vorgänge mit Ringen der gleichen Größe oder kleiner beschränkt.

  • Operationen mit Nicht-Ring-Ganzzahlen unterschiedlichen Typs sollten die Zahlen in einen Typ umwandeln, der alle Werte eines Operanden aufnehmen kann, oder vom Compiler zurückgewiesen werden, wenn kein geeigneter Typ vorhanden ist

Das Definieren von Ringtypen scheint die Anzahl der Integer-Typen zu verdoppeln, würde jedoch das Schreiben von portablem Code erheblich vereinfachen. Die Verwendung der gleichen vorzeichenlosen Typen für Zahlen und Ringe verringert die Anzahl der Typen, führt jedoch zu komplizierten Regeln, die es nahezu unmöglich machen, effizienten portablen Code zu schreiben.


+1 voll und ganz einverstanden. Eine "einfache" Sprache (einfach im Sinne einer kleinen Spezifikation) führt für den Programmierer nicht unbedingt zu einfachem Code oder einfacher Argumentation.
Andres F.

Großartiger Kommentar. Das Hinzufügen von Komplexität sollte in Bezug auf Kosten und Nutzen betrachtet werden.
user1071847

2

Tcl wurde vermutlich in dieser Richtung entwickelt. Die gesamte Sprache kann in nur 12 Regeln auf einer Manpage beschrieben werden . Es ist bemerkenswert einfach und konsequent.

Der Schöpfer von Tcl behauptete Folgendes als die ursprünglichen Ziele:

  • Die Sprache muss erweiterbar sein: Es muss für jede Anwendung sehr einfach sein, ihre eigenen Funktionen zu den Grundfunktionen der Sprache hinzuzufügen, und die anwendungsspezifischen Funktionen sollten natürlich aussehen, als wären sie von Anfang an in die Sprache integriert worden.
  • Die Sprache muss sehr einfach und allgemein gehalten sein, damit sie problemlos mit vielen verschiedenen Anwendungen verwendet werden kann und die von den Anwendungen bereitgestellten Funktionen nicht eingeschränkt werden.
  • Da der größte Teil der interessanten Funktionen aus der Anwendung stammt, besteht der Hauptzweck der Sprache darin, die Erweiterungen zu integrieren oder zusammenzufügen. Daher muss die Sprache über gute Integrationsmöglichkeiten verfügen.

Aus " History of Tcl " - http://www.tcl.tk/about/history.html


2

Wenn eine Sprache aufgrund von KISS in ihrem Design festgelegt ist, kann sie nicht wachsen. Eine Sprache, die nicht wachsen kann, wird sterben.

Im folgenden Video erklärt Guy Steele geschickt, dass eine Programmiersprache wachsen darf und warum. Wenn Sie KISS anwenden, wie kann dann eine Sprache wachsen, denn sobald sie freigegeben ist, sind ihre Werkzeuge festgelegt und dürfen sich niemals ändern.

Guy Steeles Keynote auf der ACM OOPSLA-Konferenz 1998 zum Thema "Eine Sprache wachsen lassen" befasst sich mit der Bedeutung und den Problemen beim Entwerfen einer Programmiersprache, die von den Benutzern erweitert werden kann.

Es ist eine Stunde lang, aber sehenswert. Wenn Sie nicht wissen, wer Guy Steele ist, sollten Sie wirklich über Sprachdesign sprechen.

Ich wähle dieses Video als Antwort, da ich der Meinung bin, dass die Anwendung von KISS auf Sprachdesign im Allgemeinen falsch ist, und hoffe, dass die Rede einer bekannten Person für Sprachdesign dazu beiträgt, Ihr Verständnis für die Zukunft des Sprachdesigns zu erweitern.

Da Sie hierher gekommen sind, um etwas über Sprachdesign zu lernen, und ich Ihnen einen Grund gegeben habe, KISS nicht zu verwenden, ist es nur fair, dass ich auf etwas hinweise, das mir beim Sprachdesign hilft. Kognitive Dimensionen von Notationen

BEARBEITEN

Als ich die obige Antwort schrieb, beruhte sie auf den Überlegungen von: Wenn eine Engine nur mit einem festen Satz von Tools gewartet werden kann, besteht meine Neuformulierung dieser Bedeutung in Bezug auf das Sprachdesign darin, dass sich eine Sprache nach der Veröffentlichung nicht ändern kann. Die Kommentare weisen darauf hin, dass dies nicht gemeint war. Lassen Sie mich diese modifizierte Antwort vorlegen, die dem überarbeiteten Verständnis besser entspricht.

Wenn man sich die kognitiven Dimensionen von Notationen anschaut, dann lernt man, dass es viele konkurrierende Dimensionen gibt, die mit Sprachdesign verbunden sind, als nur Einfachheit, und wenn man sich zu stark auf eine konzentriert, leidet man unter anderen. Bei der Frage , ob Einfachheit (KISS) im Vordergrund steht, habe ich die Rede von Guy Steele eingereicht, um zu zeigen, dass der Versuch, ein Design nur einfach zu halten, Auswirkungen auf andere Dimensionen hat. Noch wichtiger ist, dass ich zu vermitteln versuche, dass Sie sich viele Dimensionen ansehen und die Vor- und Nachteile davon abwägen müssen, nicht nur die Einfachheit.


3
Was passiert also, wenn das Video nicht mehr verfügbar ist? Oder wenn es in einigen Ländern nicht zugänglich ist? Deine Antwort sollte vollständig und in sich geschlossen sein. Bitte aktualisiere sie, um uns zumindest eine kurze Zusammenfassung des Videos zu geben. Nur-Link-Antworten sind nicht wirklich hilfreich und können jederzeit entfernt werden.
Yannis

3
@AndreasScheinert Die Anleitung zur Beantwortung macht deutlich, dass Links immer von Zusammenfassungen und / oder relevanten Zitaten begleitet sein müssen.
Thomas Owens

3
Ich bin nicht sicher, ob ich Ihrer Einschätzung zustimmen kann. Tcl zum Beispiel ist bemerkenswert einfach. Es dauerte Jahre mit nur 11 Regeln für die Verwendung. So einfach es auch ist, es ist in den mehr als 20 Jahren seines Bestehens erheblich gewachsen. Es hat jetzt 12 Regeln, was beweist, dass nicht nur die Bibliothek gewachsen ist, sondern dass auch ihre grundlegende Natur gewachsen ist, während sie ihre Einfachheit beibehält.
Bryan Oakley

1
"Wenn Sie KISS anwenden, wie kann dann eine Sprache wachsen, denn sobald sie veröffentlicht wurde, sind ihre Tools festgelegt und dürfen sich nie mehr ändern.": Es kommt darauf an, was Sie mit einfach und wachsend meinen. Meinen Sie das Hinzufügen neuer Bibliotheken (auf Englisch, Hinzufügen neuer Wörter zum Vokabular) oder das Hinzufügen neuer Sprachkonstrukte (auf Englisch würde dies das Hinzufügen von z. B. neuen Zeitformen, neuen Präpositionen usw. bedeuten)? Natürliche Sprachen fügen schließlich keine neuen Grammatikregeln mehr hinzu, während sie ständig neue Wörter hinzufügen. In meiner Intuition bezieht sich einfach eher auf die Anzahl der Grammatikregeln als auf die Anzahl der Bibliotheken / Wörter.
Giorgio

3
@Guy Coder: Andererseits scheint das Video, zu dem Sie einen Link gepostet haben, etwas anderes zu sagen, als Sie zu Beginn Ihrer Antwort gesagt haben, nämlich dass eine Sprache bestimmte Kernfunktionen bieten sollte, die es ihren Benutzern (Programmierern) ermöglichen erweitern Sie die Sprache (fügen Sie neue Bibliotheken hinzu). Es heißt nicht, dass die Kernsprache auf unbestimmte Zeit wachsen sollte.
Giorgio

1

Hier ist ein großes Zitat von Bruce McKinneys Hardcore Visual Basic , das den Designern von BASIC, Kemeny und Kurtz die Worte in den Mund legt . Betont meine.

Jede Computersprache hat ihr eigenes Gefühl, ihre eigene Atmosphäre, ihren eigenen Geist. Du kannst diesen Geist nicht wirklich definieren, aber du weißt, was es ist, wenn du es siehst. Ich betrachte Basic als das Gegenteil einer Aussage, die Albert Einstein zugeschrieben wird:

Machen Sie die Dinge so einfach wie möglich - aber nicht einfacher.

Wäre dieses Zitat von den ursprünglichen Designern von Basic, John Kemeny und Thomas Kurtz geschrieben worden, hätte es sich weiter vereinfacht:

Machen Sie die Dinge einfacher als möglich.

Das ist der Widerspruch, mit dem Hardcore-Visual-Basic-Programmierer leben. Wir möchten, dass die Dinge einfach, elegant und intuitiv sind - aber das ist nicht der Fall. Wir wollen, dass unsere Programme die Realität abbilden - aber das tun sie nicht. Wir möchten, dass unsere Sprache so funktioniert, wie wir denken, nicht wie Computer oder Betriebssysteme - aber wir sind nicht bereit, den Preis dafür zu zahlen .


In einem verwandten Sinne bedeutet die Tatsache, dass ein Sprachkonstrukt für mehrere Zwecke "hergestellt" werden kann, nicht, dass ein solches Design unterschiedlichen Konstrukten für diese unterschiedlichen Zwecke vorzuziehen ist. Beispielsweise verwendet C vorzeichenlose Typen, um sowohl numerische Größen als auch Elemente eines umhüllenden algebraischen Rings darzustellen. Das Hinzufügen einer Zahl beliebiger Größe oder Signifikanz zu einem Ring sollte zu einem Mitglied desselben Rings führen, während das Hinzufügen von zwei Zahlen beliebiger Größe und Signifikanz zu einem Ergebnis führen sollte, das groß genug ist, um jeden Wert eines Operanden zu verarbeiten. Verwenden von nicht signierten Typen für beide Zwecke ...
Supercat

... bedeutet, dass Cs Regeln sie manchmal als Zahlen und manchmal als Ringmitglieder betrachten müssen, so dass es fast unmöglich ist, sauberen, tragbaren Code zu schreiben.
Supercat

1

Aber kann das KISS-Prinzip auch auf die Gestaltung von Programmiersprachen angewendet werden? Kennen Sie Programmiersprachen, die speziell für dieses Prinzip entwickelt wurden, um "einem durchschnittlichen Programmierer unter normalen Arbeitsbedingungen zu ermöglichen, mit geringstem kognitiven Aufwand so viel Code wie möglich zu schreiben und zu pflegen"?

Es ist gut, dass Sie klargestellt haben, was Sie unter "einfach" verstehen, denn meiner Meinung nach ist eine einfache Programmiersprache eine Sprache mit minimaler Syntax und wenigen Funktionen (Schema, Forth, ML), die sich nicht direkt in Ihre Definition übersetzen lässt. Ich denke, Sie sind wirklich auf der Suche nach Sprachdesign mit Blick auf RAD (Rapid Application Development), und es gibt einige davon. Siehe diesen StackOverflow-Thread, zum Beispiel: /programming/66227/what-is-the-best-multi-platform-rad-language


"Weil in meinen Augen eine einfache Programmiersprache eine mit minimaler Syntax und wenigen Funktionen ist (Schema, Forth, ML)": Nun, eigentlich habe ich die Definition aus Wikipedia kopiert, aber ich neige dazu, die beiden Dinge zu identifizieren. ZB kann Schema sehr schnell erlernt werden und danach kann ich mich auf das zu lösende Problem konzentrieren. Andere Sprachen (wie C ++, das ich bei der Arbeit benutze) wachsen ständig und man muss ständig neue Dinge lernen. Außerdem ist Code weniger wartbar, da verschiedene Programmierer dazu neigen, unterschiedliche Teilmengen der Sprache zu verwenden. Daher würde ich SML und Schema als "einfach" betrachten.
Giorgio

1

Ich bin überrascht, dass noch niemand C erwähnt hat, obwohl es die Einfachheit in mehreren wichtigen Punkten in den Vordergrund stellt, oftmals so radikal, dass Programmierer die Einfachheit nicht schätzen:

  • Es gibt keine versteckte Magie. Wenn du schreibsta + b in C , haben Sie die Garantie, dass es höchstens zu einer einzelnen Assembler-Anweisung kompiliert wird.

    Selbst in relativ einfachen Sprachen wie Java kann eine einfache Anweisung a + bmehrere Mikrosekunden dauern (wenn die Variablen Zeichenfolgen sind). Andere Sprachen tragen viel, viel mehr zum extremen Beispiel von C ++ beia + b möglicherweise überladen ist, um rosa Elefanten erscheinen zu lassen. Nicht so in C: Wenn es sich nicht um einen Funktionsaufruf handelt, dauert es nicht länger als ein paar Nanosekunden. Diese Vorhersagbarkeit der Leistung ist eines der Hauptmerkmale von C und sicherlich eine Form der Einfachheit.

  • Die Datentypen sind so einfach wie möglich und beschreiben dennoch alle interessanten Datenstrukturen, die Sie möglicherweise im Speicher erstellen möchten: Es gibt nur die grundlegenden Typen, die eine CPU verarbeiten kann + Aggregation (struct ) + Wiederholung (Arrays) + Verweise (Zeiger) ).

    Es ist wahr, dass die verschiedenen Lisp-basierten Sprachen in dieser Hinsicht viel einfacher sind als C. Sie versuchen jedoch nicht, es dem Programmierer zu ermöglichen, den Speicher wie C frei zu manipulieren.

  • Orthogonalität von Features: Sie können die Features frei kombinieren und sie werden wie erwartet zusammenarbeiten. Viele Sprachen scheitern daran, dass bestimmte Konstrukte nur in definierten Kontexten vorkommen.

    Nehmen wir zum Beispiel Arrays variabler Länge in C und C ++: C ermöglicht Laufzeitlängen überall, während die liberalsten Anforderungen zur Erweiterung des C ++ - Standards sie nur in bestimmten Kontexten wie automatischen Arrays und sogar dort nur in der ersten Dimension zulassen. Auf diese Weise kann C echte mehrdimensionale Arrays mit Größen verarbeiten, die nur zur Laufzeit bekannt sind, wohingegen C ++ - Programmierer weniger schreiben müssendata[k + (j + i*lineLength)*lineCount] .

    Ein weiteres Beispiel hierfür ist der Zeiger: Ein Datenzeiger in C ist eigentlich nichts anderes als eine Variable, die eine Speicheradresse einer anderen Variablen enthält. Da der Zeiger selbst eine Variable ist, ist der Doppelzeiger eine gut definierte Sache. Dh gegeben was intund int*sind, es ist klar was sein int**muss. Vergleichen Sie dies mit C ++ - Referenzen, bei denen Sie absolut keine Ahnung haben, welche int&&Bedeutung intund gegeben ist int&!)

Es ist wahr, dass genau diese Einfachheit C so viel Hass eingebracht hat: Die Einfachheit der Sprache ermöglicht den Programmierern mehr Freiheit als gut für sie, was zu vielen Problemen mit undefiniertem Verhalten und falschen Zeigern führt. Besonders die Einfachheit der Orthogonalität, die es einem Programmierer ermöglicht, eine Variable so zu definieren, wie int (*array[m])(struct foo* (*arg)[n])sie den Lesern Kopfschmerzen bereitet, da wirklich komplexe Dinge durch die großzügige Kombination einiger einfacher Merkmale in sehr prägnanter Form ausgedrückt werden können . Dies ist die Art von Einfachheit, in der sich C auszeichnet und die ihm den Ruf gibt, eine schwer zu verwendende Sprache zu sein.

Darüber hinaus zwingt die Einfachheit der Sprache den Programmierer dazu, viel mehr Code als funktionsreiche Sprachen zu schreiben, was eine fruchtbarere Grundlage für das Aufblühen von Fehlern darstellt. Trotzdem bleibt es die einfachste mögliche Hochsprache, wenn Ihr primäres Ziel darin besteht, einen realen Computer und keine virtuelle Maschine zu programmieren.


Kann der Downvoter eine Nachricht hinterlassen, in der der Grund für die Abstimmung erläutert wird?
Giorgio

C ist ein Durcheinander. Versuchen Sie herauszufinden, was Sie erhalten, wenn Sie einen signierten Short zu einem nicht signierten Long hinzufügen, und speichern Sie das Ergebnis in einem int. Auch ohne "long long" gibt es acht verschiedene Integer-Typen. Das ist nicht einfach
Simon B

@ SimonB Du hast offensichtlich nicht verstanden, worum es in meinem Beitrag geht. Die Einfachheit der Integer-Typen ist folgende: Ein Integer-Typ hat eine Größe (in Bytes und Bits) und kann vorzeichenbehaftet oder vorzeichenlos sein. Sie können eine beliebige Kombination dieser beiden orthogonalen Merkmale verwenden. Es ist diese Orthogonalität, von der ich spreche. C verfügt über alle Funktionen, die erforderlich sind, um echte Hardware voll auszunutzen, und die eine gewisse Komplexität mit sich bringen. Die Art und Weise, wie C mit dieser Komplexität umgeht, besteht jedoch darin, einfache Konzepte orthogonal zu kombinieren, damit der Programmierer komplexe Aufgaben erledigen kann.
cmaster

0

Java Wikipedia - obwohl in Wikipedia nicht explizit angegeben, wurde Vereinfachung mehrmals erwähnt und war ein ursprüngliches Entwurfsziel, da die einzige ernsthafte OO-fähige (lose verwendete) Sprache in jenen Tagen C ++ war, das, wie wir alle wissen, mächtig ist hat aber mehr als ein paar fallen für die unachtsamen.

Die JVM sollte die plattformübergreifende Entwicklung vereinfachen, und "Write Once Run Anywhere" wurde für einige Jahre zu einem Java-Mantra. Auch hier war die Absicht, das Framework einfach bereitzustellen.

Ich glaube, C # fällt in diese Kategorie der Vereinfachung der Sprache.


Meinen Sie damit, dass C # ursprünglich auch als Vereinfachung von C ++ konzipiert wurde?
Giorgio

2
C ++ und OO? Alan Kay glaubt das nicht. C # Sinplyfication ???? Ich weiß nicht, was du mit einfach meinst. Ich denke, es wäre am besten, wenn Sie dies angeben, bevor Sie die Dinge als solche deklarieren. LISP ist einfach, da es nur sehr wenige Syntax hat. C # hat im Gegenteil Tonnen von Syntax und Schlüsselwörtern.
AndreasScheinert

Die Möglichkeit, die plattformübergreifende Entwicklung zu vereinfachen, bedeutet nicht, dass die Sprache selbst einfach ist. Etwas kann plattformübergreifend und doch nicht einfach sein.
Bryan Oakley

@Bryan Agreed - Bei der Entwicklung von Java wurde berücksichtigt, dass plattformübergreifende Programme (zu diesem Zeitpunkt) nicht einfach waren. Um einfache Programme zu erstellen, brauchten Sie eine einfache Sprache und mussten die Komplexität der Verarbeitung von plattformspezifischem Code im Programm selbst beseitigen.
Mattnz

2
@ Giorgio C # war eine Neuinterpretation von Java. Java sollte sowohl weniger komplex als C ++ sein (z. B. keine Mehrfachvererbung) als auch viel umfangreicher (z. B. umfangreiche Standardbibliothek, Garbage Collection).
Sean McSomething

-2

Hm ... diese Frage ist eigentlich schwer positiv zu beantworten, denn wenn ich an die Einfachheit des Programmiersprachendesigns denke (und an das, was einfacher zu bearbeiten ist), denke ich sofort an:

  1. "Lesbarkeit" von Code - wie gut die Sprache Objekte, Methoden usw. einkapselt
  2. Die Konsistenz der Sprach-APIs und -Schnittstellen.

Es gibt eine Reihe von Sprachen, die diese Dinge gut können - aber was mir in den Sinn kommt, ist eine Sprache, die es nicht tut die Dinge als Programmiersprache gut macht: PHP.

[Haftungsausschluss - Ich habe PHP geschrieben und PHP ist für einfache Webprojekte immer noch meine Sprache. Dies ist eine Kritik der Liebe ...]

Erstens ist PHP gut für die Umgebung, in der es normalerweise auf Webservern ausgeführt wird. Es ist einfach einzurichten, leicht zu warten usw.

Wo ich mit PHP zu kämpfen habe: Wenn Sie etwas "Ungewöhnliches" tun möchten - etwas, das Sie normalerweise nicht regelmäßig tun (wenn ich daran denke, dass ein SOAP-Webdienst in Anspruch genommen wird - etwas, das ich nicht habe Wenn Sie viel mit PHP gemacht haben, haben Sie zwei Möglichkeiten:

1) Verschiedene Open Source-Erweiterungen für PHP. Das PHP-Objektmodell ist locker genug, wo das Interface-Design auch von Bibliothek zu Bibliothek, Entwickler zu Entwickler, nicht besonders konsistent ist. Wenn Sie mit einem Satz Code konfrontiert werden, in dem jemand eine Bibliothek verwendet hat, von der Sie noch nie gehört haben, verbringen Sie viel Zeit damit, herauszufinden, was zum Teufel das macht, da die Sprache das Erstellen loser APIs / Bibliotheken ermöglicht.

2) Die "eingebauten" Funktionen - von denen es viele gibt . Ich habe ein paar Hasenlöcher durchlaufen, um entweder eine andere Bibliothek zu finden oder ein bisschen Funktionalität zu implementieren, um später darauf zu stoßenimpossiblyfound_basefunction()

Einfachheit ist meiner Meinung nach Konsistenz.


-3

Der KISS-Ansatz für Programmiersprachen ist ein lustiger Begriff, zumindest wenn Sie Programmiersprachen als Abstraktionsschicht für den Befehlssatz einer CPU usw. betrachten. Wenn Sie "KISS" nicht genauer definieren. Ich sage hier nur, dass ein Ochsenkarren KISS ist, der in vollem Umfang auf ein Auto angewendet wird.

Jetzt könnte eine andere Interpretation von KISS so etwas wie "intelligent gemacht ohne unnötige Ornamente und nicht allzu kompliziert" sein. Insbesondere könnte man argumentieren, dass es nicht zu viele spezifische Fälle für ähnliche Dinge usw. geben sollte. Normalerweise ist Mathematik ziemlich gut darin, Dinge auf den Punkt zu bringen, und - o Wunder - Mathematiker haben einige Zeit damit verbracht, über Programmierung und Computer nachzudenken .

Für die Programmierung existieren 2 recht berühmte abstrakte Modelle:

  • Eine ist die Turing-Maschine, die eine Maschine und ein einfaches Anweisungsmodell definiert, das alles berechnen kann, was ein Computer kann.
  • Der andere ist der Lambda-Kalkül von Church et. al. das ist äquivalent in der Macht

Eine lustige Sache ist: Während die Turing-Maschine in ihrem Layout recht einfach ist, ist sie kein einfach zu handhabendes System, und ich glaube nicht, dass sie für "smart KISS" geeignet ist. Aber Lambda-Kalkül hat mehr mit bekannten Programmiersprachen zu tun - und mit den wegweisenden Lisp- und Schema-Funktionen des Lambda-Kalküls hat es seinen Weg in viele Sprachen gefunden.

Lisp und Scheme sind WIRKLICH einfach, zumindest syntaktisch. Die Syntax ist ein großes Problem bei Programmiersprachen (weshalb sie wahrscheinlich immer wieder neu erfunden werden). Im Fall von C ++ kann das menschliche Gehirn kaum vorhersagen, wie einige Quellzeilen vom Compiler interpretiert werden.)

Lisps reduzieren die syntaktische Komplexität insgesamt, indem sie eine gemeinsame Form für Befehle einführen:

(command param1 param2 ...)

Dies kann ein Methodenaufruf sein, z

(max 1 2 3 4)

sowie eine if-Verzweigung, Schleife etc.

(if (< 1 2) 
    (write 4)
    (write 5))

(Der gesamte Code hier ist Pseudo-Lisp / Dialekt-Agnostiker)

Die Form

(command param1 param2 ...)

kann auch als Liste interpretiert werden

(item1 item2 item3)

Und das ist die Basis für Lisps Einfachheit und Schönheit. Weil verschachtelte Listen (wie im ifAnweisungsbeispiel) Bäume darstellen und diese sowohl von der Maschine als auch vom Menschen vor der Maschine leicht verstanden werden können.

Ein weiteres Merkmal von Lisps sind Makros, auf die ich hier nicht näher eingehen werde, aber da es keinen syntaktischen Unterschied zwischen normalen Funktionsaufrufen und "Syntax (Ei für Schleifen, Variablendeklaration usw.) gibt, muss der Parser alles in anderen behandeln Programmiersprachen) können Sie Ihre eigene Syntax erstellen.Makros sind im Wesentlichen Manipulationen des Baums , aus dem sich Ihr Programm zusammensetzt.

Ich denke, Lisp hat einen KUSS zum Programmieren. Dass Sie die Syntax mithilfe von Makros manipulieren können, hat zu einem Phänomen geführt, das Lisp sehr dynamisch entwickelt hat. Benötigen Sie eine neue Sprachfunktion wie - sagen wir Objektorientierung - schreiben Sie einfach ein OOP-System mit Makros!

Während C 2-mal um OOP-Features erweitert wurde (C ++, Obj. C), wurde Lisp mehrfach erweitert, am Ende gab es einen Gewinner.

Das ist eine weitere Besonderheit von Lisp, die sich entwickelt (siehe Clojure und Clojurescript für eine interessante neue Mutation von Lisp).

Aufgrund seiner KISS-Eigenschaften wird Lisps von einigen als Sprachlehrer bevorzugt. Wie Fogus in seinem Entwurf einer Bildungssprache umreißt ( http://blog.fogus.me/2013/01/21/enfield-a-programming-language-designed-for-pedagogy/ )

Zunächst bin ich der festen Überzeugung, dass es beim Erlernen neuer und manchmal komplexer Themen geradezu abträglich ist, die Schüler mit leichtfertigen Syntaxregeln zu überladen. Daher wurde Enfield mit minimalen Syntaxregeln entworfen und was ist minimaler als eine Lisp-ähnliche Syntax.

2
OP definiert KISS für den Kontext dieser Frage ziemlich klar: "Lassen Sie einen durchschnittlichen Programmierer unter durchschnittlichen Arbeitsbedingungen so viel Code wie möglich mit dem geringsten kognitiven Aufwand schreiben und warten" . OP erwähnt auch "interessiert über die (dokumentierten) Absichten der Designer zu lernen, anstatt Ihre persönliche Meinung über eine bestimmte Programmiersprache"
gnat
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.