Eigene Programmiersprache
-
Wurden Klassen in Python wirklich nachträglich reingefrickelt? In welcher Python-Version gabs denn noch keine Klassen?
-
Bashar schrieb:
Wurden Klassen in Python wirklich nachträglich reingefrickelt? In welcher Python-Version gabs denn noch keine Klassen?
http://python-history.blogspot.com/2009/02/adding-support-for-user-defined-classes.html
-
ein Objektmodell draufklatschen und ein bisschen was funktionales, map reduction und lambda etwa, ist heute ein Muß :xmas2:
Warum programmiert ihr nicht was Schönes Neues in Erlang oder Prolog oder helft sonstwie einer existierenden Sprache in die Zukunft, die es verdient hat ?
-
Ethon schrieb:
Danke er meint dass du immer ein self (ist wie this in C++) vor einen Zugriff schreiben musst, auch wenn die Variable/Funktion standardmäßig in der Klasse definiert ist. Angesichts der Tatsache dass du in Python aber auch lustig zur Runtime neue Variablen/Funktionen in eine Klasse stopfen kannst, finde ich das garnicht mal so tragisch.
Nein, damit kann man schon noch leben. Ich meine das:
class Foobar: def eineMethode(self, arg1, arg2): print arg1, arg2 f = Foobar() f.eineMethode(1, 2)
Könnt ja mal das self weglassen und dann ausführen, dann erhält man
>>> f.eineMethode(1,2) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: eineMethode() takes exactly 2 arguments (3 given)
Dabei könnte der Interpreter ja wenigstens per Kommandozeilenparameter beim Parsen der Methoden-Definition warnen wenn die nicht mit self anfängt. Statt dessen geht es erst beim Aufruf schief und wer sonst normale Sprachen gewohnt ist vergisst das schonmal
Finde Python aber immernoch besser als Java von daher will ich nicht meckern bzw. erkenne an, dass man in beiden schnell etwas umsetzen kann (in Python natürlich schneller). Aber eine schöne Sprache wie Ruby reizt mich einfach mehr, damit arbeite ich dann auch wirklich gerne.
-
Tippgeber schrieb:
Dabei könnte der Interpreter ja wenigstens per Kommandozeilenparameter beim Parsen der Methoden-Definition warnen wenn die nicht mit self anfängt. Statt dessen geht es erst beim Aufruf schief und wer sonst normale Sprachen gewohnt ist vergisst das schonmal
Der Bezeichner
self
ist eine reine Konvention, das geht also nicht so einfach.BTW F# hat etwas ähnliches. Es muss auch explizit ein
self
-Parameter (der auch nicht so heißen muss) angegeben werden, der aber syntaktisch an seiner natürlichen Stelle steht, so dass man ihn (eigentlich?) nicht vergessen kann. Etwa so:member self.eineMethode y = self.z * y
(Disclaimer: Bin noch beim Lernen und syntaktisch nicht so sattelfest.)
-
Bashar schrieb:
Tippgeber schrieb:
Dabei könnte der Interpreter ja wenigstens per Kommandozeilenparameter beim Parsen der Methoden-Definition warnen wenn die nicht mit self anfängt. Statt dessen geht es erst beim Aufruf schief und wer sonst normale Sprachen gewohnt ist vergisst das schonmal
Der Bezeichner
self
ist eine reine Konvention, das geht also nicht so einfach.Dass ist mir bewusst, aber es ändert nichts an der Möglichkeit Warnungen dafür zu unterstützen. Ob man den Namen nun direkt mit self vergleicht ist mit einem Namen der als Kommandoargument angegeben wurde spielt dafür ja keine rolle. Ansonsten stellt sich noch die frage wie viele Leute hier etwas anderes verwenden
-
Tippgeber schrieb:
Dass ist mir bewusst, aber es ändert nichts an der Möglichkeit Warnungen dafür zu unterstützen. Ob man den Namen nun direkt mit self vergleicht ist mit einem Namen der als Kommandoargument angegeben wurde spielt dafür ja keine rolle. Ansonsten stellt sich noch die frage wie viele Leute hier etwas anderes verwenden
Was ist ein Kommandoargument?
Aber wie willst du wissen ob folgender code OK ist oder das self vergessen wurde:def f(a,b,c): return a.foo + b.foo + c.foo
ist a jetzt korrekt self oder nicht?
-
Shade Of Mine schrieb:
Was ist ein Kommandoargument?
Er meint beim Aufruf des Interpreters.
python --self=this
würde dann erlauben, dass der self-Parameterthis
heißt. Eine Methode ohnethis
würde dann bei ihrer Definition eine Warnung hervorrufen.
-
Bashar schrieb:
Shade Of Mine schrieb:
Was ist ein Kommandoargument?
Er meint beim Aufruf des Interpreters.
python --self=this
würde dann erlauben, dass der self-Parameterthis
heißt. Eine Methode ohnethis
würde dann bei ihrer Definition eine Warnung hervorrufen.Und wie würde man das mit externen Libraries machen?
Ich müsste dann ja quasi pro .py Datei definieren können wie self heisst.Ne, einfach immer self verwenden und statische code analyse verwenden um solche Fehler zu finden. Aber um ehrlich zu sein, ich hatte noch nie einen Bug in einer Python Anwendung der auf ein fehlendes self zurückzuführen war...
-
es wirkt aber trotzdem hochgradig künstlich, wie umgeschult auf objektorientiert.
-
Für meine experimentellen Programmiersprachen habe ich folgende Komponenten benötigt:
- Lexer
- Parser
- Erstellung von deBruijn-Indizes oder Symbol-Tabellen
- Typ-Inferenz oder Typ-Checker (falls erwünscht)
- Interpreter oder Code-Generator
Für Lexer und Parser kann man sich einfache Parser-Kombinatoren schreiben, dann braucht man keinen Parser-Generator.
DeBruijn-Indizes sind hilfreich, um in den Stack oder in Umgebungen zur Laufzeit zu indizieren.
Für Typ-Inferenz braucht man Unifikation; Typ-Checker sind in der Regel einfacher zu schreiben. In Sprachen wie Python gehört der Checker zur Laufzeit-Umgebung.
Wenn man eine Sprache kennt, die der eigenen ähnlich ist, bietet sich zunächst ein Code-Generator für diese Sprache an, das macht am Anfang am wenigste Arbeit.
C/C++ geht natürlich als Zielsprache, sofern kein garbage collector benötigt wird.
Ein Interpreter macht zwar ein wenig mehr Arbeit, aber auch mehr Spaß bei Benutzung.Auf jeden Fall fängt der Stress erst nach dem Parsen an, denn zu Parsern findet sich im Internet viel.
Wenn man nicht alles verstehen will, sondern nur die Sprache bauen will, bieten sich Bibliotheken an.
Man kommt auch ohne aus, aber mit gehts schneller:- Parsec, JParsec, FParsec, scala.util.parsing.combinator, Boost::Spirit, je nach Sprache für Lexer/Parser
- Tabellen finden sich in den meisten Sprachen, für die Erstellung von deBruijn-Indizes benutzt man funktional Listen, imperativ kann man einen Stack benutzen.
- Als Typ-Inferenz könnte man Prolog benutzen oder "constraint-programming"-Bibliotheken. (letztere hab ich noch nie benutzt)
- Als Code-Generator kann man die LLVM in C++ oder OCaml benutzen. .NET bietet "Reflection", um bytecode zu erstellen.
Funktionale Sprachen (Haskell/ML/F#/Scala) sind zu empfehlen, um den Compiler/Interpreter zu schreiben, aber nicht zwingend notwendig, C# oder Python gehen auch. Funktionaler Code ist in der Regel kürzer.
Als Inspiration für Typ-Systeme oder neue Programmiersprachen kann Types&Programming Languages dienen,
Parser-Kombinatoren und deBruijn-Indizes sind in MLftw erklärt, ebenso wie der Lambda-Kalkül.
In das Drachenbuch habe ich mal reingelesen um LALR-Parser zu verstehen, aber das war nicht so schön erklärt und eher weniger verständlich. Ich kenne aber nur die deutsche Version, vielleicht ist die englische besser.Ich hoffe, dass die Anregungen helfen! Je mehr Leute verstehen wie man Compiler schreibt, desto besser!
-
Danke alf42red für den guten Beitrag.
Aber eine neue Frage. Meine Sprache ist mittlerweile für triviale Sachen zu gebrauchen, bis jetzt interpretiere ich sie.
Jetzt habe ich mich gefragt, ob es zufälligerweise eine primitive Metasprache + passenden Compiler gibt, um Binaries zu erzeugen. Zum Beispiel dass ich eine XML-Representation meines ASTs erzeuge und das kompilieren kann. (Einen eigenen Code-Generator schreiben oder mit LLVM würde ich ungern machen, würde lieber mehr high-level bleiben und etwas auf dem Niveau von XML ausgeben).Mich stört es nämlich gerade etwas, die Eigenheiten von C++ erdulden zu müssen, die teilweise auch limitieren.
-
Du kannst deine Sprache auch nach C(++) konvertieren und dann kompilieren.
-
Das Drachenbuch ist total wirr und unverstaendlich geschrieben. Keine Ahnung, wieso das Ding ein Standardwerk sein soll. Vielleicht weil man sich selber unglaublich schlau fuehlen kann, wenn man sowas empfiehlt (so a la "ich hab das Buch verstanden und alles damit verstanden").
-
Ethon schrieb:
Jetzt habe ich mich gefragt, ob es zufälligerweise eine primitive Metasprache + passenden Compiler gibt, um Binaries zu erzeugen.
Vielleicht C--.
-
maximAL schrieb:
Du kannst deine Sprache auch nach C(++) konvertieren und dann kompilieren.
Mache ich ja zur Zeit. Aber zb Metainformationen (und davon generiere ich gewaltige Mengen, ist ja Teil des Konzepts) müssen zur Laufzeit in eine HashMap gestopft werden, das könnte theoretisch bei Nutzcode die Startzeiten unangenehm drücken. Ich hätte die Hashtable lieber bei der Kompilierung fertig da. Klar könnte man das mit einem MTP-Feuerwerk irgendwie zusammenfrickeln, hab ich aber irgendwie wenig Lust drauf.
-
Ich habe vor einigen Jahren auch begonnen eine Programmiersprache zu entwickeln, die - obwohl ich noch keine Version rausgegeben habe - schon eine gewisse Historie besitzt.
Vom Drachenbuch rate ich ebenfalls ab. Zum Thema Parserbau ist es uninteressant und bei der semantischen Analyse - also da, wo es spannend wird - hält es sich recht bedeckt.
Es ist ein Must-Have, aber kein Must-Read.@Ethon: Mein Focus liegt auf praktischem Nutzen. Ich möchte eine Sprache, die sehr restriktiv arbeitet, um den Programmierer semantisch prüfbare Fehler möglichst nicht zu erlauben. Wenn er ein "Hello World" programmieren soll und schreibt ein "Salut Monde" kann ich natürlich auch nix mehr machen.
Welche Metadaten möchtest Du sammeln und vor allem warum?
-
Welche Metadaten möchtest Du sammeln und vor allem warum?
Ich halte es für eine coole Idee, über ein Netzwerk nativen Code senden und ausführen zu können. Das ganze aber komplett ohne Festplattenaktivität und sicher.
Deswegen schippt jedes Modul Metainfo über alle Funktionen oä mit, ob sie threadsafe ist, welche Parameter sie erwartet etc.Damit zb soetwas funktioniert:
remote_module io("http://example.com/io.mod") io::file "test.txt" => test io::write test "Hello from io"
Hier muss zur Runtime gecheckt werden ob es eine Klasse file in io gibt, ob es eine Funktion gibt um ein Objekt von einem String zu kontruieren, das selbe für write. Sobald das geschehen ist wird mit Funktionszeigern gearbeitet, dh. der Overhead schwindet.
-
Ethon schrieb:
Welche Metadaten möchtest Du sammeln und vor allem warum?
Ich halte es für eine coole Idee, über ein Netzwerk nativen Code senden und ausführen zu können. Das ganze aber komplett ohne Festplattenaktivität und sicher.
"Sicher" ist da so ein Punkt, wenn Daten aus dem Internet kommen.
Nativer Code geht auch nicht, denn wer sagt denn, dass ich mit einem Intel-kompatiblen Rechner das Programm ausführen möchte?Hier müssen also noch einige Schichten dazwischen geplant werden.
Und es stellt sich automatisch die Frage, ob die Aufgabe clientseitig oder serverseitig ausgeführt werden soll. Eine Sprache, die Netzwerkunterstützung voraussetzt, sollte hier ebenfalls einen Plan haben.
Die Idee ist "cool". Aber Maßstab sollte sein, ob's praktisch ist.
Lass Dir von mir nichts ausreden, den Spruch in der Signatur habe ich, weil man mir auch immer sagt, dass das, was ich mache, nicht gemacht werden kann.Ethon schrieb:
Deswegen schippt jedes Modul Metainfo über alle Funktionen oä mit, ob sie threadsafe ist, welche Parameter sie erwartet etc.
Damit zb soetwas funktioniert:
Okay, hier kommen wir wieder überein, das ist nicht ganz das, was ich unter Meta-Inforamtion erwartet habe.
Du suchst hier weniger eine neue Programmiersprache als ein alternatives Objekt-Format. Das von Dir beschriebene könnte nahezu direkt über C++ abgedeckt werden. Wozu also eine neue Sprache, wenn Du Dein Problem mit einer vorhandenen erweitern kannst? Zumal Du den Lernaufwand für die Nutzer gering hältst.
-
Wie gesagt, das Ganze ist in erster Linie zum Spaß bzw zum Lernen da, deswegen versuch ich es so aufzubauen, wie es möglichst wenig andere Sprachen machen. Zu 99.99% wird die Sprache nie produktiv genutzt werden.
Nativer Code geht auch nicht, denn wer sagt denn, dass ich mit einem Intel-kompatiblen Rechner das Programm ausführen möchte?
Das Modul soll zumindestens mitschippen, auf welcher Plattform mit welchem OS das Ganze lauffähig sein soll, da kann der Loader zur Laufzeit noch meckern, wenn er da etwas falsches vorgesetzt bekommen hat. Wie man es am Besten machen kann dass genau das richtige Modul geladen wird ... keine Ahnung.
Warscheinlich am besten mit Namenskonventionen.
Und es stellt sich automatisch die Frage, ob die Aufgabe clientseitig oder serverseitig ausgeführt werden soll. Eine Sprache, die Netzwerkunterstützung voraussetzt, sollte hier ebenfalls einen Plan haben.
Stimmt.
Du suchst hier weniger eine neue Programmiersprache als ein alternatives Objekt-Format. Das von Dir beschriebene könnte nahezu direkt über C++ abgedeckt werden. Wozu also eine neue Sprache, wenn Du Dein Problem mit einer vorhandenen erweitern kannst? Zumal Du den Lernaufwand für die Nutzer gering hältst.
Naja, zum Beispiel den Aufruf von nicht threadsicheren Funktionen zu blockieren, wenn die aufrufende Funktion als threadsicher markiert wurde etc, scheint mir per C++ nicht möglich zu sein.