Wie würden Sie eine Programmiersprache entwerfen? [geschlossen]


41

Wenn Sie eine Programmiersprache entwerfen würden, wie würden Sie das tun? Welche Funktionen würden Sie hinzufügen? Was würden Sie weglassen? Statisch oder dynamisch getippt? Stark oder schwach getippt? Zusammengestellt oder interpretiert? Begründen Sie Ihre Antworten.


12
Diese Frage ist zu vage. Sprachmerkmale können erst diskutiert werden, wenn der Zweck der Sprache festgelegt ist.
blucz

1
Wenn Sie abstimmen können und denken, dass dies eine nützliche Frage ist, oder wenn Sie unten nützliche Antworten haben, stimmen Sie ab. StackExchange-Sites benötigen Stimmen, um eine gute Community aufzubauen. Sie können 30 Stimmen pro Tag abgeben, verschwenden Sie sie nicht. Speziell Anwender mit hohem Ansehen und niedrigen Zählen erhaltenen Stimmen lesen Sie bitte diesen: meta.programmers.stackexchange.com/questions/393/...
Maniero

3
Ich würde eine Sprache auf sehr hohem Niveau mit einer Methode erstellen: public void DoWhatIMeant ();
Dave

6
Die ideale Programmiersprache? ... Ich würde den Compiler dazu bringen, meine Gedanken zu lesen und ein Programm genau so zu generieren, wie ich es möchte. :) Es könnte eine Weile dauern, aber es würde sich lohnen.
WalterJ89

2
Zusammenstellung und Interpretation sind Eigenschaften von ... nun, dem Compiler oder Interpreter (duh), nicht der Sprache. Alle Sprachen können von einem Compiler oder einem Interpreter implementiert werden. Und tatsächlich sind es so ziemlich alle. Es gibt Compiler für Ruby, Python, ECMAScript, PHP, es gibt Interpreter für C, C ++, Java, Haskell, ...
Jörg W Mittag

Antworten:


55
  • Ich denke definitiv, dass funktionierende Programmiersprachen ankommen werden, also wird meine Sprache funktionieren. Siehe Zähmen von Effekten mit funktionaler Programmierung

  • Ich denke, die CPUs werden bald Hunderte von Kernen haben, und Threads werden eine Hölle für ihn sein. Das Actor Model ist also ein Muss anstelle von Threads. Siehe Erlang - Software für eine gleichzeitige Welt

  • Ich denke auch, dass OOP fehlgeschlagen ist, die Kommunikation zwischen Objekten wurde als asynchron angenommen . Ich denke, wir müssen Nachrichten weitergeben , mit unveränderlichen Nachrichten. Senden und vergessen. Wie im Actor-Modell. Siehe Objektorientierte Programmierung: Der falsche Pfad?

  • Ich denke, dass es gut wäre, statische Typisierung zu haben , so dass Fehler früher im Entwicklungszyklus aufgefangen werden. Ich würde jedoch die Typinferenz wie in Haskell verwenden, damit der Entwickler den Typ nicht überall im Code wie in C, C # und Java schreiben muss. Siehe Learn You A Haskell für großartiges Wohl

  • Ich würde auch eine großartige UI-Bibliothek mit deklarativem Layout wie in WPF und Android entwerfen . Ich hätte es aber gerne so wie bei Functional Reactive Programming .

Meine Sprache wäre also wie die Parallelität in Erlang, aber mit der Eingabe wie in Haskell und einem GUI-Framework wie in WPF.NET.


4
Klingt nach Scala, abgesehen von der großartigen UI-Bibliothek.
Ape-inago

Ich dachte, Scala hatte Message Passing und Schauspieler. Ich denke, ich weiß nicht, wie das mit OOP zusammenhängt.
Ape-inago,

@Jonas: Sieht toll aus :) Ich weiß nicht viel über das Actor Model, ist es ähnlich wie das, was Go mit den Goroutinen gemacht hat?
Matthieu M.

1
Das einzige, was ich skeptisch finde, ist das statische Tippen. Ich würde definitiv starkes statt schwaches Tippen bevorzugen, aber manchmal ist statisches Tippen zu restriktiv. Aber ich kenne Haskell nicht und habe nur gute Dinge über sein Schreibsystem gehört :)
sakisk

1
Offen gesagt ist das Versagen von OOP, dass kaum eine "objektorientierte" Sprache sie tatsächlich implementiert . Am einfachsten schustern Sie ein Objektmodell in eine prozedurale Sprache und nennen es einen Tag. Ich wünschte, Smalltalk hätte mehr von sich selbst mitbekommen, anstatt jeden prozedursprachigen Trottel aufzufordern zu sagen, "Eh, wir können so etwas irgendwie machen - vielleicht auch so" und es schaffen, den Punkt von OOP gänzlich zu verfehlen.
CHAO

22

Hinweis: Ich habe C-ähnliche Syntax verwendet, um Funktionen in diesem Beitrag zu beschreiben, aber ich bin nicht wählerisch in Bezug auf die Syntax selbst, solange es nicht lächerlich ist, wenn alle Schlüsselwörter CAPS sind.

1. System eingeben

Die wichtigste Funktion, die ich in einer Sprache haben möchte, ist das statische Tippen mit optionalem dynamischem Tippen. Der Grund dafür ist, dass Sie mit der statischen Typisierung a) Fehler eher früh als spät abfangen können und b) der meiste Code implizit statisch typisiert ist, unabhängig davon, ob die Sprache die Unterscheidung trifft oder nicht. Es gibt jedoch mehrere Anwendungsfälle, in denen die dynamische Eingabe äußerst nützlich ist. Wenn Sie beispielsweise Daten aus einer Datei lesen, gibt es häufig Felder unterschiedlichen Typs, und die dynamische Typisierung vereinfacht heterogene Container. Meine ideale Sprache würde also ungefähr so ​​aussehen:

//variable declarations
int anInt = 42 //anInt is now irrevocably an integer and assigning another type to it is an error
vartype aVariable = 42 //aVariable is currently an integer, but any type can be assigned to it in the future

//function definitions
int countElements(Collection c)
{
  return c.count();
} 

//c HAS to be a collection, since countElements doesn't make sense otherwise

void addToCollection(Collection& c, vartype v) 
{
  c.append(v)
}

//c is passed by reference here

2. Kompiliert vs. interpretiert

Ich möchte, dass die Sprache entweder im Voraus kompiliert wird oder dass JIT kompiliert, aber nicht nur interpretiert wird, da Geschwindigkeit der Grund ist. Dies knüpft an Punkt 1 an , da es für einen optimierenden Compiler / Jitter viel einfacher ist, statisch getippten Code zu optimieren, und dynamisch getippten Code einfach so zu belassen, wie er ist.

3. Abschlüsse

Die Sprache muss funktionale Programmierkonstrukte unterstützen, und Funktionen müssen erstklassige Objekte sein.

4. Objektorientiert

Die Sprache sollte es Ihnen ermöglichen, objektorientierten Code zu schreiben, aber auch einfachen Imperativ-Code sollte erlaubt sein. Das heißt, es sollte möglich sein, ein Hallo-Welt-Programm wie folgt zu schreiben:

int main(string<> args=null)
{
  printf("hello, world"); 
  return 0;
}

// this code also demonstrates two other features,
// default arguments for functions (not explained further)
// and immutable lists like string<> (see 6. Built-in datatypes)

5. Namespaces

Namespaces sind eine gute Sache. Sehr wenig Material sollte in den globalen Namespace gelangen. Aber wenn Sie müssen Sachen im globalen Namespace setzen, können Sie (ala C ++).

6. Eingebaute Datentypen

Die Sprache muss als integrierte Datentypen die folgenden Konstrukte aufweisen:

  • Ein intoder mehrere Datentypen. Wenn es nur einen intTyp gibt, sollte der Bereich unbegrenzt sein. Wenn es mehr gibt, sollte implizites Upcasting in den kleinsten Typ erfolgen, der das Ergebnis einer Berechnung aufnehmen kann, wobei der Typ mit unbegrenzter Reichweite der größte ist.
  • Ein einzelner integrierter Binärtyp float, der einem IEEE 754 entsprichtdouble
  • Ein veränderlicher listTyp, der entweder als doppelt verknüpfte Liste oder als Block zusammenhängender Speicherhaltezeiger auf jedes Element implementiert wird
  • Ein unveränderlicher listTyp, der sich wie ein Array verhält, dessen Größe jedoch nach der Erstellung nicht geändert werden kann
  • Mutable und unveränderliche stringTypen, wobei der Standard unveränderlich ist.
  • Ein mapoder ein dictTyp, der veränderlich ist und unveränderliche Schlüssel sowie veränderliche und / oder unveränderliche Werte enthält.
  • Die integrierten Auflistungstypen sollten standardmäßig homogen typisiert sein, können jedoch vartypebei Bedarf geändert werden
  • Ein booleanTyp
  • Ein nulloder ein noneTyp, der einer Variablen eines beliebigen Typs zugewiesen werden kann.
  • Veränderbare und unveränderliche setTypen
  • Ein decimalTyp, der dezimale Gleitkommavariablen implementiert
  • Ein fixedTyp, der eine Festkommazahl implementiert

Die decimal, floatund fixedTypen sollen die Anteil exakt gleiche öffentliche Schnittstelle (entweder durch Vererbung oder Ente eingeben), so dass sie transparent und von Funktionen zurückübergeben werden. Der übergeordnete Typ könnte aufgerufen werden real.

7. Rufen Sie nach Wert und Referenz auf

Sie sollten in der Lage sein, Funktionen sowohl nach Wert als auch nach Referenz aufzurufen, wobei der Standardwert value ist (dh, eine Kopie des Arguments wird erstellt und in der Funktion bearbeitet).

8. Zeiger

Die Sprache sollte Zeiger haben und Zeigerarithmetik erlauben. Zeiger können nur statisch getippt werden (um den Alptraum zu vermeiden, der a ist void*). vartypeZeiger sind ausdrücklich verboten. Mit Zeigern und Zeigerarithmetik kann die Sprache ernsthaft als Systemprogrammiersprache verwendet werden.

9. Inline-Montage

In Verbindung mit 8. sollte die Sprache Inline-Assemblersprachencode für Situationen zulassen, in denen dies erforderlich ist.

10. Sicherheit

Die Sprache sollte größtenteils sicher sein, Ausnahmebehandlung usw. unterstützen. Zeigerarithmetik und Inline-Assemblierung können in Teile des Codes verschoben werden, die ausdrücklich als unsicher gekennzeichnet sind. Unsicherer Code ist zulässig, wird jedoch dringend empfohlen.

11. Undefiniertes Verhalten

Der Sprachstandard sollte festlegen, wie sich das Programm unter allen Umständen verhalten soll, außer in Code, der explizit als unsicher markiert ist, dh es sollte kein undefiniertes Verhalten außerhalb unsicherer Blöcke geben. Auf diese Weise kann die Sprache als funktionsfähige Anwendungsentwicklungssprache verwendet werden, und Sie können trotzdem sagen, dass Sie ein Betriebssystem darin schreiben können.

Das ist alles, woran ich im Moment denken kann, aber ich bearbeite / aktualisiere den Beitrag, wenn ich an mehr Dinge denke.


5
Schauen Sie sich "D Programming Language" an: digitalmars.com/d
Wizard79

Soweit ich mich erinnern kann, verfügt D weder über eine optionale dynamische Typisierung noch über einen integrierten Ganzzahltyp mit unbegrenztem Bereich. Der Integer-Typ ist kein so großes Problem, aber das Fehlen einer optionalen dynamischen Typisierung macht ihn ziemlich unattraktiv.
Chinmay Kanchi

1
Ich würde hier wirklich einen decimalTyp hinzufügen .
Konfigurator

3
"Ein Null- oder kein-Typ, der einer Variablen eines beliebigen Typs zugewiesen werden kann." - Einschließlich Boolean? :-p
Timwi

1
Ich sehe "flexibel" im ursprünglichen Beitrag nicht. Inline Assembler würde mir als oberste Voraussetzung für eine Programmiersprache nicht in den Sinn kommen. Vielleicht ist das laut Felix von Leitner heutzutage, dass Assembler meist langsam falsche Ergebnisse liefert.
LennyProgrammers

7

So würde meine Traum-Programmiersprache aussehen:

  • Ein leistungsstarkes statisches Typsystem mit Unterstützung für abhängiges Schreiben.
  • Optionale dynamische Eingabe.
  • Numerischer Turm a la Lisp, jedoch statisch getippt.
  • Makros a la Lisp.
  • In erster Linie eine funktionale Programmiersprache mit grundlegender Unterstützung für die imperative Programmierung (wie die ML-Familie).
  • Müllabfuhr.
  • Inferenz eingeben.
  • Fortsetzungen.
  • Optionale Lazy-Semantik.
  • Alle Steuerungskonstrukte würden in Form von Bibliotheksfunktionen bereitgestellt. (Dies kann mit den letzten beiden Funktionen möglich gemacht werden.)
  • Minimale Syntax (nicht so wenig wie Lisps, aber so etwas wie Ioke / Seph.)

Klingt gut. Ich habe allerdings nicht wirklich eine gute Möglichkeit gesehen, statisch sichere Makros zu erstellen.
Jörg W Mittag

@ Jörg: Nemerle?
Fehlender Faktor

In Smalltalk sind alle Kontrollstrukturen tatsächlich Methoden, und es werden bei ihrer Implementierung keine Fortsetzungen verwendet. Eins wird für das andere nicht benötigt.
Oak

@Oak, kannst du Pythons yieldin Smalltalk implementieren ? Sollte so sauber zu bedienen sein.
Fehlender Faktor

Ein Yield-like-Mechanismus ist in smalltalk bereits als Bibliotheksmethode ohne Fortsetzungen implementiert.
Oak

6

Ich hätte es ziemlich ähnlich wie C # entworfen, aber Microsoft hat mich geschlagen. :)

(Außer natürlich, dass meine weniger gut durchdacht und amateurhafter gewesen wäre.)

Es macht mir nicht viel aus, ob es kompiliert oder interpretiert wird, deshalb muss ich dieses Bit nicht rechtfertigen.

Was die starke statische Typisierung angeht, fällt es mir schwer zu verstehen, warum dies überhaupt gerechtfertigt sein muss. Die statische Typisierung ist eine Funktion, mit der Fehler während der Kompilierung abgefangen werden. Dynamische Typisierung ist das Fehlen dieser Funktion und verzögert die Fehler bis zur Laufzeit. Nach meiner persönlichen Erfahrung hatte ich nur wenige Anwendungsfälle, in denen dynamisches Versenden Sinn machte und nützlich war. Die Konvolutionen, die ich in C # vor 4.0 durchlaufen musste, um es zu erhalten, waren dann leicht zu rechtfertigen. Mit C # 4.0 muss ich das nicht einmal mehr rechtfertigen, da wir jetzt einen dynamischen Versand haben.

Wahrscheinlich hätte ich jedoch eine neue Syntax erstellt, anstatt mich genauso religiös an die alte C-Syntax zu halten wie C #. Die switch-Anweisung ist besonders schrecklich, und ich mag auch die cast-Syntax nicht (es ist der falsche Weg). Ich mache keine großen Aufregungen um die Details der Syntax, daher muss ich sie nicht im Detail begründen, außer dass ich sie nicht so ausführlich wie Visual Basic haben möchte.

Was soll ich sonst noch rechtfertigen?


+1 Gute Antwort! Ich werde später auch einen meiner eigenen posten.
Chinmay Kanchi

4
C # ist eine mächtige Sprache, aber die Syntax ist oft unübersichtlich. Ich denke, das liegt daran, dass so viele dieser Funktionen nicht im Originaldesign enthalten waren.
Casebash

Daher "4.0", denke ich.
Mark C

5

Nun, hier ist eine Liste der Funktionen, die ich hinzugefügt habe:


Lisp-ähnliche Syntax

Lisp-Stil

Vorteile :

  • Leicht erweiterbare Syntax. Haben Sie jemals versucht, eine foreach-Schleife in C zu implementieren? Das ist nicht gerade einfach. (Wohlgemerkt, ich habe es geschafft ).
  • Homoikonizität. Sie können einfach(eval "your data files")

Nachteile :

  • Geschachtelte polnische Notation ist oft schwer zu lesen

Funktionale Programmierung

Haskell-Stil

Vorteile :

  • Einfache Parallelität, der gesamte Code ist threadsicher.

Nachteile :

  • Es ist schwierig, Nebenwirkungen in reinen Funktionscode zu implementieren, obwohl Monaden einen guten Job zu machen scheinen.

Starke dynamische Eingabe

Python-Stil

Vorteile :

  • Dynamische Eingabe macht sauber lesbaren Code. Starke Eingabe kann Schreibfehler beseitigen

Implementierung :

Erlaube Funktionsüberladung basierend auf Typen, ähnlich wie bei CLs defgeneric:

(define (+ (a <int>) (b <int>))
  (ints-add a b))

(define (+ (a <string>) (b <string>))
  (string-concat a b))

(define (+ a b)
  (add-generic a b))

Kompilierbar und interpretierbar

Vorteile :

  • Leistungssteigerung beim Kompilieren (normalerweise wahr, nicht immer)

Nachteile :

  • Kann Funktionen in der Sprache einschränken, llvm wäre jedoch eine gute Unterstützung.

Systemprogrammierung

C-Stil

Vorteile :

  • Spricht einen geringfügig größeren Benutzerkreis an.
  • Einfachere Interaktion zwischen Anwendungen, Kernel und Gerätetreibern, wenn alle in derselben Sprache geschrieben sind

Nachteile :

  • Schränkt die Abstraktionen in der Sprache ein, ist dynamisches Tippen oft nicht geeignet.

Hygienemakros (CL-Stil und Schema-Stil)

Vorteile :

  • Einfache Erweiterung der Sprache, insbesondere mit der Lispy ™ -Syntax
  • Ich habe das schon mal gesagt, oder?

Nachteile :

  • Nicht viele, wenn Sie mit Lispy ™ -Syntax fertig sind

Denken Sie mal darüber nach, dieses Schema definiert mehr oder weniger, abgesehen vom Kompilierungs- und Systemprogrammierungsbit. Das kann umgangen werden, indem libguile verwendet und diese Bits in C geschrieben werden.


1
Schauen Sie sich Ioke und Seph an. Es ist erstaunlich, wie viel einfacher eine Sprache zu lesen ist, wenn man im Vergleich zu S-Expressions nur eine winzige Menge an Syntax hinzufügt und trotzdem über die vollständigen Makrofunktionen verfügt. (Anstelle von "jeder Funktionsaufruf ist eine Liste und Listen sind erstklassig" ist "alles ist ein Nachrichtensend und Nachrichtenketten sind erstklassig". Anstelle einer Liste, deren carFunktion und cdrArgumente sind, haben Sie eine Objekt, dessen nameFeld die Methode ist und dessen argumentsFeld die Argumente. Und anstatt zu verschachteln, haben Sie prevund nextZeigerfelder.)
Jörg W Mittag

Klingt ziemlich genau wie Clojure (vorausgesetzt, Sie verwenden Mjolnir für die native Codegenerierung auf LLVM für den Systemprogrammierungsteil - github.com/halgari/mjolnir )
mikera

3

Es gibt mehrere Sprachen, die ich für verdammt gut halte (C # ist derzeit mein Favorit). Da dies meine Fantasiesprache ist, möchte ich, dass es Folgendes gibt:

  • Kick-ass offizielle API-Dokumentation. Die Java-API ist so gut, und C # /. NET ist ziemlich gut. Ruby / Rails ist hier ziemlich schrecklich.
  • Kick-ass offizielle allgemeine Dokumentation (Anleitungen, allgemeine Verwendungen, viele Beispielcodes). C # / .Net ist dafür gut.
  • Eine riesige Community blogbasierter Dokumentatoren und StackOverflow-Problemlöser, die mir aus schwierigen Situationen heraushelfen
  • Eine breite Palette von gut unterstützten, gut dokumentierten und leistungsstarken Plugins / Bibliotheken / Erweiterungen (Ruby / Rails hat 'leistungsstark', aber keine der beiden anderen).
  • Ist einigermaßen stabil - ändert nicht alles, um die meisten vorhandenen Codes auf jährlicher Basis zu brechen (siehe Sie, Ruby / Rails).
  • Ist nicht zu stabil - kann sich an Fortschritte im Sprachdesign anpassen (Sie sehen, C ++)

2
"Kick-ass documentation" -Punkte sollten PHP enthalten: D
Corey

3

Compiler Hinweise

Ich rede aus meinem Hintern, weil ich nicht so viel über Sprachdesign weiß, aber ich denke, dass die Funktion, über die ich spreche, Hinweise in anderen Sprachen heißt. Compiler-Hinweise vielleicht?

Ich weiß nicht, ob ich das in einem Perl6-Entwurf gelesen habe oder gerade hoch war, aber ich stelle mir eine Sprache vor, in der standardmäßig alles locker, goosy und automagisch ist. Aber wenn Sie die Leistung wirklich steigern und sagen möchten, hey, dieser Wert ist immer eine Ganzzahl oder er ist nie null, oder dies kann parallel sein, oder dies ist zustandslos, solche Dinge ... Dass der Compiler automatisch in die Stadt gehen könnte auf diesen speziell gekennzeichneten Bereichen.

E: Ich würde mich über Kommentare freuen, die erläutern, wonach ich frage, oder Beispiele anführen, wo dies bereits vorhanden ist.


1
Sie können dies in Common Lisp tun. Sie können dem Compiler beispielsweise mitteilen, dass i eine Ganzzahl mit einer angemessenen Größe ist. Eine nützliche Sache ist , dass durch die unterschiedlichen safetyund speedWerte, können Sie oft entweder die Compiler Prüfung bestehen und durch (finden Probleme) oder übernehmen , was Sie sagen , wahr ist (und kompiliert schnelleren Code).
David Thornley

2

So probieren Sie neue Ideen aus:

Ich würde eine dynamische funktionale Programmiersprache erstellen, mit der Sie alle Tricks für Anweisungsausdrücke und die einfachste Lambda-Syntax mit Pattern Matching ausführen können. Abseitsregel aktiviert.

// a view pattern (or Active Pattern in F#)
default = \def val: !!val.Type val def

// usage of the pattern
greet = \name<(default "world") `and` hasType Str>:
  p "Hello, \{name}!"

(p "Enter your name", .input).greet // (, ) is a sequence expression, returning the last value

Hier ist eine Erklärung:

default =Legt den Speicher fest, \def valbeginnt eine Curry-Funktion mit zwei Argumenten, val.Typeist dasselbe wie Type[val], !!konvertiert in Boolean und kann angewendet werden, also valunddef are after it.

f x= f[x]= x.f .f=f[]

und in greet, verwendet name<(default "world")und hasType Str>bedeutet, dass das Muster default "world"verwendet und gebunden wird name. Das Standardmuster gibt einen Standardwert an. andist ein weiteres Muster, das zwei Muster miteinander verkettet. Das defaultMuster kann nicht scheitern, solange hasTypees scheitern kann. In diesem Fall wird eine Ausnahme ausgelöst.

Variablen sind Speicher, die funktional übergeben werden können, und Speichertabellen können Referenzen sein, die erstellt und gelöscht werden, wenn sich der Gültigkeitsbereich ändert.

Hashes und dergleichen werden wie in Lua und JavaScript sein.

Wenn ich eine kompilierte Sprache erstellen möchte, erstelle ich ein F # für Java mit Haskell-ähnlichen Funktionen. Es ist eine reine funktionale Sprache, mit der Ausnahme, dass es eine Funktion gibt, die Quotations und Comp Exprs miteinander mischt, um durch Schreiben von pseudocode-ähnlichen Blöcken eine zwingende Programmierung zu erreichen.


1
Es klingt ein bisschen wie Erlang, eine dynamisch getippte funktionale Programmiersprache, die um eine ganz eigene gleichzeitige Sprachkonstruktion ergänzt wird.
Jonas

2

In Anbetracht dessen, dass ich nur PHP und Javascript kenne und dass ich vor dem Entwerfen einer Sprache unbedingt ein paar weitere lernen sollte:

Syntax: Denken Sie sorgfältig über Funktionsnamen und Argumentreihenfolge nach (dh seien Sie weniger chaotisch als PHP).

Features: Eine Reihe von stringFunktionen, die Variablen als Folge von Bytes verarbeiten, jedoch keinen Text verstehen, und eine Reihe von textFunktionen, die viele Codierungen verstehen und mit UTF-8 und anderen Multibyte-Zeichenfolgen arbeiten können. (Und lassen Sie Codierungsprüfungen in die Sprache integrieren, mit einer Funktion, text.isValidEncoding(text, encoding)die Ihnen anzeigt, ob eine Byte-Sequenz fehlerhaft und unsicher als Text zu behandeln ist.

Ich denke, ich mag die Idee der starken statischen Typisierung, aber ich habe sie nie benutzt, also kann ich nicht wirklich sagen.


2

Bevor ich eine Programmiersprache entwerfe, würde ich eine gute Antwort auf die Frage finden: Warum brauchen wir noch eine andere Programmiersprache? Rosetta Code listet zum Zeitpunkt des Schreibens 344 Sprachen auf. Wenn keiner von diesen meinen Bedürfnissen entspräche, würden die genauen Gründe, warum sie dies nicht taten, den Ausgangspunkt bestimmen (Sprachen, die am nächsten kommen) und was dazukommen würde.

Wenn ich im Lotto gewinnen würde und aus irgendeinem Grund nichts Besseres zu tun hätte, würde ich mit Liskell anfangen und es zu einer vollwertigen Sprache machen, im Gegensatz zu einem GHC-Front-End, und dann FFI einfacher (und automatisierter) machen, damit ich jedes verwenden könnte C / C ++ Bibliothek.


2

Eine gute Sprache ist eine Sprache, die ist:

  • leicht zu überlegen (keine obskure Syntax)
  • Lassen Sie Ihre Ideen mit minimaler Verzerrung ausdrücken
  • verstecke die wirklich wichtigen Details vor dir (Optimierung / Ressourcenverwaltung)
  • leicht parallelisierbar (mehrere Kerne, verteiltes Rechnen)

Es ist ziemlich schwer, daraus eine Liste von Funktionen zu machen, aber ich denke, dass funktionale Programmierung, obwohl sie sich nicht natürlich anfühlt , näher daran ist als zwingende Programmierung (insbesondere , wenn es darum geht, kleinste Details zu verbergen).

  • C-Schnittstelle : C ist die Verkehrssprache der Programmiersprachen, und die Anzahl der in C entwickelten Bibliotheken ist erstaunlich. Durch eine einfache Schnittstelle (wie Python) zu C profitiert die Sprache automatisch von all diesen Bibliotheken und ermöglicht es auch, schwere Aufgaben zu senden, die für eine metallnahe Sprache nicht optimiert werden konnten.
  • Verteilt : Ich mag Go's beim Multithreading, mit einfachen Routinen, die die Laufzeit abhängig von ihrer Aktivität auf Threads verteilt. Eine solche Sprache ermutigt den Programmierer, über Aufgaben nachzudenken und sie voneinander zu isolieren.
  • Müllabfuhr : heutzutage selbstverständlich;)
  • Unveränderlich : Viel einfacher, über etwas nachzudenken , das niemals mutieren kann, viel einfacher, Multithreading / verteiltes Computing zu implementieren (Sie müssen nur synchronisieren, um die Lebensdauer zu bewältigen, die die Compiler-Aufgabe darstellt)
  • Lambdas : geht mit erstklassigen Funktionen, denke ich
  • Message Passing : Unveränderlichkeit bedeutet kein Mutex, daher folgen wir dem Vorschlag von Tony Hoares
  • Module : Ähnlich wie Namespaces, jedoch mit besserer Kapselung
  • Reflexion : Die verteilte Berechnung erfordert eine Serialisierung, die dem Compiler überlassen werden sollte, und die Deserialisierung lässt sich mit einer bestimmten Form der Reflexion leichter erreichen.
  • Static Strong Typing : Je früher ein Fehler erkannt wird, desto geringer sind die Kosten

Im Moment ist die Sprache, die dieser Liste am nächsten kommt, wahrscheinlich Haskell:

  • es fehlen Routinen: Ich habe noch keinen natürlichen Weg gesehen, um Parallelität in Haskell auszudrücken (obwohl es vielleicht meine Unwissenheit ist ...)
  • Es hat eine obskure Syntax: Irgendwie sieht es so aus, als würden Haskell-Programmierer eher seltsame Operatoren als Worte verwenden. Es mag glatt erscheinen, aber es hilft nicht viel, um zu verstehen, was los ist.

2

Auf deine erste Frage "Wie würdest du das machen?" - eine kurze Antwort würde ich nicht geben. Ich habe nicht genug Parser / Compiler-Theorie, um das durchzuziehen. Aber ich programmiere seit 25 Jahren, also habe ich einige Ideen und Meinungen, die ich teilen kann.

Zunächst würde ich versuchen, einen OOP-Ansatz zu finden, mit dem Sie wirklich verbundene Modelle erstellen können. Was ich damit meine ist, dass Modelle eines der wichtigsten Dinge in fast jeder Art von Programmierprojekt sind - es ist immer viel Grunzarbeit und kontinuierliches Refactoring, um es richtig zu machen, und ich tadele dies an einem Mangel an echter Konnektivität in OO Sprachen.

Erlaube mir zu demonstrieren. Angenommen, ein Klassenhaus hat eine Door-Eigenschaft.

var door = house.Door;

Sie haben jetzt eine lokale Variable mit einem Verweis auf die Door-Instanz.

Aber bedenken Sie, was gerade passiert ist: Sie haben gerade die Tür vom Haus gerissen, und jetzt sind Sie ziemlich glücklich, die Tür herumgereicht zu haben, und der Rest Ihres Codes weiß nicht, dass diese Tür tatsächlich mit einem Haus verbunden ist.

Für mich ist das grundsätzlich falsch.

Und ja, ich weiß, dies kann "leicht" von Fall zu Fall behoben werden - in diesem Fall durch Beibehalten eines umgekehrten Verweises von jeder Tür zu dem Haus, an dem es gegenwärtig angebracht ist. Hierdurch wird Ihr Modell natürlich fehleranfällig, da Sie nun zwei umgekehrte Verweise genau pflegen müssen, sodass Sie die Eigenschaften House.Doors und Door.House als privat kennzeichnen und Methoden wie House.AddDoor (), House.RemoveDoor () hinzufügen. ), Door.SetHouse () usw. und verdrahten Sie alles und testen Sie die Einheit, um sicherzustellen, dass es tatsächlich funktioniert.

Klingt das nicht nach viel Arbeit, um eine so direkte Beziehung zu modellieren? Viel Code zu pflegen? Eine Menge Code, der umgestaltet werden muss, während sich das Modell weiterentwickelt?

Das Problem sind Zeiger. Jede OO-Sprache, die ich gesehen habe, leidet von Natur aus unter der Tatsache, dass eine Objektreferenz wirklich ein Zeiger ist, denn das ist, was Computer verwenden.

Zeiger sind kein guter Weg, um die reale Welt zu modellieren. Unabhängig davon, welche Welt Sie modellieren möchten, ist fast garantiert, dass alle Beziehungen in dieser Welt wechselseitige Beziehungen sind. Zeiger zeigen nur in eine Richtung.

Ich würde gerne eine Sprache sehen, in der das grundlegende Datenmodell ein Diagramm ist - wobei alle Beziehungen standardmäßig zwei Enden haben. Dies würde mit ziemlicher Sicherheit eine viel natürlichere Möglichkeit bieten, die reale Welt zu modellieren. Dies ist das einzige, wofür wir überhaupt Computer benötigen. (das und Videospiele.)

Ich habe keine Ahnung, wie die Syntax für eine solche Sprache aussehen würde oder ob sie sich überhaupt mit Text ausdrücken lässt. (Ich habe mich gefragt, ob eine solche Sprache irgendwie grafisch sein müsste ...)

Ich möchte auch, dass alle Formen des zufälligen Zustands beseitigt werden.

Zum Beispiel verbringen wir in der Webentwicklung viel Zeit damit, Daten aus Datenbanken in Geschäftsmodelle, in Darstellungsmodelle umzuwandeln ... dann werden einige dieser Daten in Formularen dargestellt, was wirklich nur eine weitere Transformation darstellt. .. und state kommt von Form-Posts zurück, und dann formen wir diese Daten um und projizieren sie zurück auf das Ansichtsmodell, z. B. Ansichtsmodellbinder und so weiter. Wir projizieren dann vom Ansichtsmodell zurück auf das Geschäftsmodell. model ... Wir verwenden dann objektrelationale Mapper (oder Grunts), um die Daten aus dem Ansichtsmodell zu transformieren und in eine relationale Datenbank zu projizieren ...

Fängt das an, redundant zu klingen? Zu welchem ​​Zeitpunkt haben wir während dieses ganzen Wahnsinns wirklich etwas Nützliches erreicht? Und mit nützlich meine ich etwas Greifbares - etwas, das der Endbenutzer verstehen und sich darum kümmern kann. Letztendlich sind die Stunden, die Sie damit verbracht haben, etwas zu erstellen, das die Benutzer überhaupt verstehen können, wirklich die einzigen Stunden, die Sie gut ausgegeben haben. Alles andere sind Nebenwirkungen.

Ich möchte eine sehr dynamische Sprache. Der Schreib- / Kompilier- / Ausführungszyklus ist eine mühsame Zeitverschwendung. Im Idealfall sollte die Sprache nur herausfinden, was sich geändert hat, und bei Bedarf transparent im Hintergrund kompilieren / laden.

Im Idealfall sollten Sie nicht einmal auf "Ausführen" klicken müssen - Dinge sollten auf dem Bildschirm geschehen, während Sie Änderungen vornehmen, die Ihre Änderungen sofort widerspiegeln. Das Problem mit dem Write / Compile / Run-Zyklus oder sogar mit dem direkteren Write / Run-Zyklus ist, dass Sie zu weit von dem entfernt sind, was Sie tun - um sich mit unserer Arbeit verbunden zu fühlen brauche sofortiges Feedback, sofortige Ergebnisse. Das Warten ist zu lang!

Wiederum weiß ich nicht einmal, ob dies mit einer traditionellen IDE erreicht werden könnte oder ob dies eine völlig neue Art von Schnittstelle erfordern würde.

Sie sollten in der Lage sein, eine Mischung aus schwacher und starker Eingabe zu verwenden, je nachdem, was für das Problem, an dem Sie arbeiten, am besten geeignet ist.

Der Status im Allgemeinen sollte etwas sein, das die Sprache für Sie vollständig beherrscht. Warum sollten Sie sich aus Gründen der Persistenz auf eine Datenbank verlassen müssen? Im Idealfall möchte ich einfach die Lebensdauer einer Variablen im Modell angeben können: eine Webanforderung, eine Sitzung, 24 Stunden, permanent.

Warum müssen wir uns zwischen einer ganzen Reihe von Speicherlösungen für unterschiedliche Medien und Laufzeiten entscheiden? - ganz zu schweigen von der Anpassung und Formung der Daten an die jeweiligen Medien; Browser-Cache, Datenbank, Speicher, Festplatte, wen interessiert das? Daten sind Daten. Wo Sie Ihre Daten speichern (und wie lange), sollte eine einfache Entscheidung sein, kein Kampf gegen die Götter!

Nun, viel Glück damit.


1

Es wäre wahrscheinlich eine Multi-Paradigma-Sprache, die Folgendes unterstützt:

  • Strukturierte / prozedurale Programmierung
  • Objekt orientierte Programmierung
  • Funktionale Programmierung

Warum diese? Objektorientiert, weil es eine großartige Möglichkeit ist, große Programme zu organisieren, insbesondere zum Organisieren der Daten. Strukturiert, weil man das nicht immer will / braucht (OOP), sollte man die Wahl haben. Funktioniert, weil es Programmierern das Debuggen erleichtert und Programme übersichtlicher macht.

Ich würde Pythons Modell mit eingerückten Blöcken verwenden, um Codeblöcke zu markieren. Es ist sehr sauber und schön zu lesen.

Ich würde ziemlich viele Ideen von Python stehlen, weil Python eine sehr nette Sprache ist. Ich würde es für Aussage nehmen und ich würde seine Karten, Liste und Tupel kopieren.

Jetzt würde ich wahrscheinlich nicht die dynamischen Konzepte von Python übernehmen: Zum einen wäre es wahrscheinlich explizit und statisch typisiert. Ich denke, die Programme werden dadurch klarer. Die Variablen wären wahrscheinlich alle Objekte mit Methoden, dann könnten Sie so etwas wie str.length()die Länge eines Strings ermitteln. In Funktionsdefinitionen müssten Sie den Rückgabetyp und die Typen der Argumente angeben (die auch generische Typen unterstützen).

Kehren wir zum Kopieren von Python zurück ;-). Ich liebe es, optionale Prozedurargumente zu haben, also würde ich das wahrscheinlich haben. Python unterstützt jedoch keine Prozedurüberladung, das würde ich mir wünschen.

Schauen wir uns die Klassen an, ich würde die Mehrfachvererbung fallen lassen. zu leicht zu missbrauchen. Ich würde private und ähnliche Bereiche implementieren und ich würde das wahrscheinlich so implementieren, wie es in C ++ gemacht wird. Ich hätte auch abstrakte Klassen und Interfaces; Ich glaube nicht, dass Python das hat.

Es würde innere Klassen unterstützen, in der Tat würde ich eine sehr mächtige objektorientierte Sprache wollen.

Es würde wahrscheinlich interpretiert werden. Mit einer guten JIT-Kompilierung ist es möglich, sehr schnell zu arbeiten (ich möchte eine schnelle Sprache, obwohl die Produktivität der Programmierer an erster Stelle steht), und die Kompilierung ist oft nur schlecht für die Produktivität. Interpretierte Sprachen fördern auch die Plattformunabhängigkeit, was von Tag zu Tag wichtiger wird.

Es hätte Unicode-Unterstützung eingebaut. Internationalisierung ist heutzutage sehr wichtig.

Es wäre definitiv Müll gesammelt. Verdammt, ich hasse es, das Speichermanagement selbst zu machen. auch nicht gut für die Produktivität.

Schließlich hätte es eine gute Standardbibliothek.

Wow, habe gerade gemerkt, wie sehr ich Python wirklich liebe.


Warum Interpreted languages also promote platform independance? Ich denke, es gibt mehr plattformübergreifende Interpreten als Compiler (in Prozent), aber konnten Sie nicht herausfinden, warum dieser Satz wahr sein sollte? Ich denke, es gibt überhaupt keinen Unterschied zwischen ihnen in Bezug auf plattformübergreifende Fähigkeiten.
Mahdi

1

Zuallererst kaufte ich ein paar Bücher über Compiler, ein paar Standards und belegte ein oder zwei Kurse in Sprachen und Compilern. Ich würde PEPs beisteuern und Sitzungen des C ++ - Standardkomitees besuchen. Ich würde den Compilern, die ich verwende, Patches beisteuern, hoffentlich sowohl für Features als auch für Bugs.

Dann gehe ich zurück und schaue entsetzt auf diese Liste, die ich gerade erstellt habe. In welche Richtung würde ich mit einer Sprache gehen, wenn ich gleich anfangen würde:

  • Funktionell , weil ich mich derzeit in keiner funktionalen Sprache auskenne und es eine großartige Möglichkeit wäre, eine Sprache zu lernen. Falls es nicht direkt folgt: alles ist konstant .
  • Ich würde es mit so viel füllen Type Inference als ich in ihm passen könnte, aber mit der Option Schnittstellen explizit angeben. Ich bin mir bei anderen Typen nicht sicher. Dies verdoppelt sich, da alle Funktionen standardmäßig generisch sind .
  • Wie Sie vielleicht erraten haben, mit Schnittstellen ; das heißt, mit Typen, die nur Versprechungen für verfügbare Operationen bieten.
  • Zu sagen, ob die Sprache stark oder schwach geschrieben ist, ist in diesem Fall, soweit ich das beurteilen kann, nicht sehr aussagekräftig. Ich würde es als stark typisiert bezeichnen, da die Dinge nie ändern, welche Schnittstellen sie implementieren .
  • Es hätte viel Design by Contract- Unterstützung. Nochmals, so viel ich passen kann: Vor- und Nachbedingungen sind ein Muss; Ich weiß nicht, wie wichtig Invarianten für die funktionale Programmierung sind.
  • Während ich dabei bin, schaue ich mir Sprachen an, in denen Sie formell die Korrektheit beweisen und sehen können, ob ich von dort etwas aufheben kann.
  • Ich würde rausgehen und eine großartige Testbibliothek schreiben . Selbst wenn es mir nicht gelingt, es großartig zu machen, werde ich zumindest eine beträchtliche Menge Zeit damit verbringen, daran zu arbeiten, da ich denke, dass es etwas ist, was jede Sprache haben sollte.
  • Was die Syntax angeht, so würde die Sprache entweder signifikante Leerzeichen haben und sehr nach Python aussehen , oder sie würde auf Lojban basieren und einen Großteil der Grammatik und des Wortschatzes teilen. Im ersten Fall würde ich mein Bestes geben, um die Grammatik einer CFG so nahe wie möglich zu bringen.
  • Es ist mir egal, ob Leute, die die Sprache implementiert haben, sie vorher kompilieren, sie JIT-fähig machen, sie interpretieren, am Lagerfeuer singen oder College-Kinder dafür bezahlen, dass sie sie für sie ausführen. Meine eigene Implementierung würde wahrscheinlich als Interpreter oder C-Compiler beginnen und schließlich zu einem JITter übergehen.

Da sich selbst diese ziemlich weit gefassten Punkte wahrscheinlich schnell ändern würden, wenn ich mit der Implementierung der Sprache beginnen würde, halte ich es für unnötig, auf weitere Details einzugehen.


0

Wenn ich Zeit hätte, würde ich eine lokalisierbare Programmiersprache entwerfen , die auf Scala basiert, sodass sie die meisten Funktionen außer wahrscheinlich XML hat. Mein Ziel ist es, eine Sprache zu schaffen, die fast auf natürliche Weise in Sprachen mit einer anderen Struktur als Englisch gelesen werden kann, beispielsweise Arabisch (meine Muttersprache). Ich denke an folgende Features:

  • Eine Preprozessor- #langDirektive, mit der der Preprozessor über die für die Programmierung verwendete menschliche Sprache informiert wird. Zum Beispiel: #lang arwürde die Verwendung des Wortes فئةanstelle von class, عرفanstelle von defusw. zulassen . Die sprachspezifischen Schlüsselwörter würden in Standard-Präprozessordateien definiert.
  • Der Vorverarbeiter würde einige optionale Schlüsselwörter entfernen, deren einziger Zweck darin besteht, dem Code Klarheit zu verleihen. Zum Beispiel würde es entfernen "besteht aus" in class MyClass is composed of {werden class MyClass {und entfernen "als" in def MyMethod(x: Int) as {werden def MyMethod(x: Int) {. In einigen (menschlichen) Sprachen würde dies das Verständnis des Codes erleichtern, insbesondere für Schüler.
  • Der Compiler würde die Verwendung der Präfixnotation für den Eigenschaftenzugriff erlauben. Dies ist für die meisten lateinischsprachigen Personen möglicherweise nicht sinnvoll, für einige andere Sprachen ist dies jedoch durchaus sinnvoll. Beispielsweise ist der Zugriff auf Eigenschaften in Arabisch normalerweise ein Präfix wie in اعرض طول اسم محمد, was dem print(length(name(Mohammad)))in Programmieren-Englisch äquivalent ist . (Die Klammern dienen der Klarheit.)

Ich glaube, dass diese minimalen Änderungen am Vorprozessor und am Compiler die Programmierung für nicht englischsprachige Benutzer erheblich vereinfachen würden.


5
Microsoft (und einige andere zuvor) haben lokalisierte Versionen von VBA (Visual Basic für Office-Anwendungen) erstellt. Es war eine Katastrophe. Während es für Neulinge, junge Leute und nicht-englische Leute schön ist, Code in ihrer Muttersprache zu lesen, ist es sehr schwierig, Code mit Leuten außerhalb Ihres Landes zu teilen. In unseren Internet-Tagen ist es nicht sehr produktiv, isoliert zu arbeiten. Wenn ich mich nur auf französische Quellen (Blog-Artikel, Bücher usw.) verlassen müsste, um Scala zu lernen (so wie ich es derzeit tue), würde ich viele nützliche Informationen vermissen.
Ganz

1
@PhiLho: Du hast sicherlich recht. Meine Hauptaufgabe bei der Erstellung einer solchen Sprache ist es jedoch, die Programmierung einem viel breiteren Publikum zugänglich zu machen, einschließlich K-12-Schülern und älteren Menschen, die möglicherweise keine Englischkenntnisse haben. In der Einführungsphase müssen sie wahrscheinlich keine externen Bibliotheken verwenden, und das Erstellen von lokalisierten Wrappern für einige kleine (z. B. print) würde nicht schaden.
Hosam Aly

1
Der andere Punkt ist, dass viele Leute bereits ihre Muttersprache für Klassen- und Methodennamen verwenden. Es hilft ihnen nicht, dass Schlüsselwörter auf Englisch sind, und es macht auch keinen Unterschied für andere Leute, da Schlüsselwörter nicht ausreichen, um nicht-englischen Code zu verstehen. Der Pre-Prozessor kann die Schlüsselwörter jedoch immer wieder auf Englisch und bei Bedarf auf eine andere Sprache zurücksetzen.
Hosam Aly
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.