Python to C Converter
@LanX: Ich sehe da die Vorteile: Es kann nicht passieren dass sich ein und der selbe Name zum Beispiel in einer Schleife in verschiedenen Durchläufen auf verschiedene Sichtbarkeitsbereiche bezieht. Und da der Compiler schon feststellt welche Namen lokal sind, wird schnellerer Code generiert. Lokale Variablen werden nämlich nicht in einem Dictionary gespeichert, sondern in einem Array und im Bytecode werden die lokalen Namen über einen festen Index referenziert.
Naja du argumentierst Python habe "richtige" Closures und dann sagste man solle OOP dafür nutzen...BlackJack hat geschrieben:Ich sehe ``nonlocal`` nicht als essentiell wichtig an. Python hat Klassen, man bekommt da also nichts, was man vorher nicht auch relativ einfach ausdrücken konnte. Klassen sind ein wichtiger Bestandteil von Python und nichts exotisches. Wenn man sie braucht, sollte man sie auch verwenden.
Es gibt halt ein riesiges funktionales Erbe aus der LISPischen ecke, wenn ich jedes Pattern erst halb auf Pythons OOP umschreiben muss, ist das nicht dasselbe wie wenn ich es direkt umsetzen kann. (wie z.B. in "Higher Order Perl" für Perl beschrieben.)
Das mag für dich nicht essentiell sein, mich schränkt es ein.
Und um den Kreis zu schließen JS bietet es vollständig an¹.
Mithilfe von Closures kannste dort die vermissten OOP Features mehr als kompensieren.
Dazu muss man sich auch in Closures wohlfühlen und denken können. Das meinte ich damit, dass ein reiner Python POV dann viele Möglichkeiten in JS übersieht.
1) zugegeben, das Fehlen von echten Blockscopes durch Curlies zwingt einen manchmal diesen Workaround mit anonymen Funktionen zu nutzen, die sofort in-place ausgeführt werden... auch etwas nervig.
Wenn man eine Methode (Funktion) eines Objektes beispielsweise an einen Event-Handler bindet verweist this nicht mehr auf das aktuelle Objekt aus dem diese Methode stammt sondern auf den Kontext des Event-Handlers. http://www.digital-web.com/articles/sco ... avascript/ Deswegen muss man dann das magische this vorher an eine lokale variable binden, um später noch auf das eigene Objekt zugreifen zu können. In Python wird das verhindert weil man auf normalem Wege nur an die „bound method“s rankommt. In anderen Sprachen (Java, C++) ergibt sich die Problematik auch nicht weil man sowieso nicht an den Funktionszeiger einer Methode rankommt ohne sich auf den Kopf zu stellen.LanX hat geschrieben:ich kann dir nicht folgen... Beispiel?Darii hat geschrieben: Das seltsame this, auf das man sich nicht verlassen kann (var self = this *hust*).
Ja. Java, C ... such dir was aus.hä??? ... gibts außer Python eine andere (nichtakademische) Sprache die per default localisiert und wo man explizit "nonlocal"-isiseren muss (wenn man denn kann)?
Wie sollte es denn sonst funktionieren? Erst ein bisschen mit der Globalen Variable a rumspielen, dann lokal machen und irgendwann später wieder zu einer globalen Variable machen. Wenn das nicht unübersichtlich wäre…"var" ist nervig weil es für den ganzen Scope - also auch vorhergehenden Code - gilt.¹
Deswegen bemängelt Crockfords JS-Lint es auch wenn du die var-Deklarationen nicht am Funktionsanfang machst.
Sprich, da es dafür in Javascript keine Sprachmittel gibt, denkt sich jeder ein eigenes System aus, um gemeinsames Verhalten in die Prototypen zu kopieren.Das ist IMHO ein fettes Plus! Ich bevorzuge - schon aus Designgründen - Mixins. Die Nützlichkeit der Mehrfachvererbung ist m.E. ein Mythos.
Das ist tatsächlich, wie es bei (korrekter) lexikografischer Bindung funktionieren sollte.Darii hat geschrieben:[Wie sollte es denn sonst funktionieren? Erst ein bisschen mit der Globalen Variable a rumspielen, dann lokal machen und irgendwann später wieder zu einer globalen Variable machen. Wenn das nicht unübersichtlich wäre…
Code: Alles auswählen
a = 1
def f():
print(a) # dies müsste eigentlich 1 sein, ist in Python aber ein Fehler
a = 2 # jetzt habe ich eine lokale Variable, die die globale überschattet
print(a) # dies müsste 2 sein
print(a) # dies ist 1
f() # müsste 1 und 2 ausgeben, bricht aber ab
print(a) # dies ist wieder 1
Code: Alles auswählen
(define a 1)
(define f (lambda ()
(print a) ; dies ist 1
(let ((a 2))
(print a)))) ; dies ist 2 (die Klammern machen die Bindung deutlicher)
(print a) ; gibt 1 aus
(f) ; gibt 1 und 2 aus
(print a) ; gibt 1 aus
Code: Alles auswählen
if (true) {
function f() { return 1; }
} else {
function f() { return 2; }
}
f();
Stefan
Das ist für Java falsch. Die Sprache verhält sich im Gegensatz zu Python so, wie bereits in meinem Scheme-Beispiel gezeigt und wie man's eigentlich erwarten würde. Für C kann ich's nicht sagen und habe keine Lust, das auszuprobieren. Ruby hingegen macht es wie Python und würde in dem folgenden Programm einen NameError liefern:Darii hat geschrieben:Ja. Java, C ... such dir was aus.hä??? ... gibts außer Python eine andere (nichtakademische) Sprache die per default localisiert und wo man explizit "nonlocal"-isiseren muss (wenn man denn kann)?
Code: Alles auswählen
a = 1
def f()
puts a
a = 2
puts a
end
f()
In einer früheren Lua-Version gab es IMHO mal die Notwendigkeit, etwas ähnliches wie "nonlocal" zu deklarieren (irgendwas mit upvals oder so), doch das man man schon vor Jahren zugunsten der gewohnten lexikografischen Bindung aufgegeben.
Stefan
Ich bezog mich auch nicht auf das nonlocal/whatever sondern auf das Verhalten, dass Variablen immer global sind. In Javascript muss/kann man ja wie in Python Variablen nicht explizit deklarieren (bis global, nonlokal, var). Die Deklaration erfolgt implizit durch Zuweisung. Wenn ich in Javascript eine Variable benutze ist sie automatisch global. Wenn ich in Java eine Variable deklariere ist sie lokal.sma hat geschrieben:Das ist für Java falsch. Die Sprache verhält sich im Gegensatz zu Python so, wie bereits in meinem Scheme-Beispiel gezeigt und wie man's eigentlich erwarten würde.Darii hat geschrieben:Ja. Java, C ... such dir was aus.hä??? ... gibts außer Python eine andere (nichtakademische) Sprache die per default localisiert und wo man explizit "nonlocal"-isiseren muss (wenn man denn kann)?
Code: Alles auswählen
function x() { foo = 23 }
x();
foo; // -> 23
Die wichtige Erkenntnis aus dem Self-Projekt (vor 20 Jahren) war, dass protoypische Vererbung mittels Delegation ein so mächtiges Sprachkonzept ist, dass man damit alle andere Systeme simulieren kann. Das man sich damit also verschiedene klassenbasierten Vererbungskonzepte selbst bauen kann, spricht IMHO für und nicht gegen die Sprache und die Wahl von Selfs System für JavaScript.Darii hat geschrieben:Sprich, da es dafür in Javascript keine Sprachmittel gibt, denkt sich jeder ein eigenes System aus, um gemeinsames Verhalten in die Prototypen zu kopieren.
Warum wurde Vererbung überhaupt erfunden? Um Code zu sparen. Es war (und ist) ein reines Implementationsmittel und man sollte (was leider nur wenige Programmiersprachen machen) eine Subtyp-Beziehung strickt von der Vererbung trennen. Einfache Vererbung ist nicht mächtig genug. Mehrfache Vererbung hat aber Probleme, wenn man statische Klassendefinitionen mit statischen Feldern hat, weil nicht klar ist, ob es diese beim "Diamand-Problem" nun mehrfach gibt oder nicht. Außerdem ist die Serialisierung gleichnamiger Methoden nicht trivial. Das simple Verfahren von Python1.x hat sich nicht bewehrt und der von Dylan stammende Algorithmus (AFAIK der einzige der bislang gefunden wurde, der sich in der Praxis bewährt) wurde erst relativ spät entdeckt und ist auch nicht gerade einfach zu verstehen. Zudem hätte es nicht "super" wie bei Smalltalk heißen dürfen, sondern besser etwas wie "next" oder "call-next-method" wie bei CommonLisp und Dylan, was klar macht, dass hier die nächste weniger spezielle Methode aufgerufen werden soll, die nicht notwendigerweise aus einer Oberklase stammt. Schon viel früher hat man entdeckt, das Mixins (ich meine, die stammen aus Flavors, einem sehr frühen objektorientierten Lisp) alle guten Eigenschaften der Mehrfachvererbung haben ohne die Probleme. Formalisiert man Mixins und fügt ihnen abstrakte Methoden hinzu, hat man traits, ich kenne diesen Begriff wieder von Self. Inzwischen greifen immer mehr Sprachen (z.B. Scala und Fortress) dazu. Self hat zudem auch einen supersimplen Ansatz, der Serialisierungsproblem von Methoden zu lösen: Bei Mehrdeutigkeit gibt es Laufzeitfehler. Das missfällt aber Sprachtheoretikern, weil man so keine Vorhersagen über das Programm machen kann, ohne es auszuführen. Ach, es gibt auch jemanden, der hat Traits für JavaScript implementiert. Rubys Module sind konzeptionell übrigens auch Mixins bzw. Traits. In Python kann man die Mehrfachvererbung ebenfalls für Mixins nutzen, wenn man will. Komischerweise macht das kaum einer und irgendwie gibt es eine Art ungeschriebenes Gesetz, doch immer noch von einer Klasse zu erben. Ich glaube ja, das liegt daran, weil sich die Leute nicht davon trennen können, Vererbung gleichzeitig als Subtyp-Hierarchie anzusehen. Hatte ich schon mal Cecil erwähnt - das ist ein Zwitter aus Self und CommonLisp mit einem optionalen statischen Typsystem, welches Vererbung und Typen korrekt trennt. War eigentlich eine recht elegante Sprache, IMHO.
Stefan
@LanX: Wenn Du LISP programmieren willst, dann programmiere doch einfach in LISP. Wenn Du Dich gedanklich nicht auf eine andere Sprache einlassen willst, sondern in ihr genau so weiterprogrammieren willst, wie in einer Sprache die Du schon kennst, warum willst Du dann überhaupt eine andere Sprache verwenden. Mit dieser Argumentation kommt die Freiheit, dass jeder in seinen eigenen Mustern schreibt, und es für andere schwierig wird den Quelltext zu verstehen, warten, und zu erweitern. Eines *der* Probleme die ich mit LISP und Scheme habe, wenn sich jeder seine eigene DSL daraus zimmert.
Umgekehrt erwarte ich auch nicht, dass andere Sprachen wie Python funktionieren, zum Beispiel das es dort eine Python-artige Vererbung gibt. Im Grunde wirfst Du hier immer unterschwellig vor, die Leute wären zu unflexibel sich auf JavaScript einzulassen und hängen an den Spracheigenschaften von Java oder Python, und im Gegenzug jammerst Du rum, dass Du Muster von LISP nicht 1:1 auf Python übertragen kannst, und Dich die Sprache tatsächlich nötigt, sich mit ihrem OOP-Modell auseinanderzusetzen.
Umgekehrt erwarte ich auch nicht, dass andere Sprachen wie Python funktionieren, zum Beispiel das es dort eine Python-artige Vererbung gibt. Im Grunde wirfst Du hier immer unterschwellig vor, die Leute wären zu unflexibel sich auf JavaScript einzulassen und hängen an den Spracheigenschaften von Java oder Python, und im Gegenzug jammerst Du rum, dass Du Muster von LISP nicht 1:1 auf Python übertragen kannst, und Dich die Sprache tatsächlich nötigt, sich mit ihrem OOP-Modell auseinanderzusetzen.
Aber im Gegensatz zu Self gibt es bei Javascript nur einen Prototypen. Bei Self kann man ja beliebig viele parent-Slots haben. JavaScript ist an der Stelle nicht flexibel genug um das mit Sprachmitteln zu auszugleichen. Ich hab nichts grundsätzliches gegen das Objektmodell von Javascript. Die Sprache selbst finde ich einfach nicht so toll (um nicht zu sagen grausam). Javascript ist einfach als reine Scriptsprache konzipiert und dementsprechend wurde sie auch entworfen. Siehe die ganzen grandiosem impliziten Typumwandlungen. Sowas ist bei dynamisch typisierten Sprachen tödlich. Dann knallt es nämlich nichtmal zur Laufzeit, sondern das Programm funktioniert einfach nicht wie gedacht.sma hat geschrieben:Die wichtige Erkenntnis aus dem Self-Projekt (vor 20 Jahren) war, dass protoypische Vererbung mittels Delegation ein so mächtiges Sprachkonzept ist, dass man damit alle andere Systeme simulieren kann. Das man sich damit also verschiedene klassenbasierten Vererbungskonzepte selbst bauen kann, spricht IMHO für und nicht gegen die Sprache und die Wahl von Selfs System für JavaScript.Darii hat geschrieben:Sprich, da es dafür in Javascript keine Sprachmittel gibt, denkt sich jeder ein eigenes System aus, um gemeinsames Verhalten in die Prototypen zu kopieren.
Man könnte auch einfach import nutzen, leider ist aus irgendeinem mir unverständlichen Grund der sternchen-Import innerhalb von Klassen „deprecated“.sma hat geschrieben:In Python kann man die Mehrfachvererbung ebenfalls für Mixins nutzen, wenn man will. Komischerweise macht das kaum einer und irgendwie gibt es eine Art ungeschriebenes Gesetz, doch immer noch von einer Klasse zu erben.
Na, hört sich an wie geh doch rüber, wenn's dir nicht passt.BlackJack hat geschrieben:@LanX: Wenn Du LISP programmieren willst, dann programmiere doch einfach in LISP.
Zurück zum Start, es ging darum dass nicht nur Javascript Defizite hat und ich z.B. bei Python "richtige Closures" und komplexe Lambdas vermisse.
Ich könnte auch ne lange Liste dessen abgeben, was ich in Perl vermisse. (Docstrings, Instanzvariablensigils wie in Ruby, Macros,...etc. pp.)
Das ist ein Diskussionsforum...wenn ich meine Kritik nicht äußere, kann ich nicht aus der Widerlegung lernen.
@Darii: Der ist nicht "deprecated". Schon in der ``import``-Doku von Python 1.4 steht der Satz `"The from form with * may only occur in a module scope."` Code der solche Importe nutzt(e) war also schon immer ausserhalb der Spezifikation, auch wenn der Compiler das früher mal durchgehen liess.
Deswegen die Anführungsstriche. Aber was heißt früher? In 2.6 gehts noch.BlackJack hat geschrieben:@Darii: Der ist nicht "deprecated". Schon in der ``import``-Doku von Python 1.4 steht der Satz `"The from form with * may only occur in a module scope."` Code der solche Importe nutzt(e) war also schon immer ausserhalb der Spezifikation, auch wenn der Compiler das früher mal durchgehen liess.
"var" ist die Deklaration, und vergleichbar zu "int" usw in C und Java.Darii hat geschrieben: In Javascript muss/kann man ja wie in Python Variablen nicht explizit deklarieren (bis global, nonlokal, var). Die Deklaration erfolgt implizit durch Zuweisung. Wenn ich in Javascript eine Variable benutze ist sie automatisch global. Wenn ich in Java eine Variable deklariere ist sie lokal.Code: Alles auswählen
function x() { foo = 23 } x(); foo; // -> 23
Die "undeklarierten" Variablen sind in JS auch nicht wirklich "global", sondern sind Attribute des umgebenden Objektes, sprich im Browser window.
Code: Alles auswählen
javascript: a="winki winki";alert(window.a)
Code: Alles auswählen
O={a:"hier"};
with (O) {alert(a)};
Habe ich doch geschrieben.LanX hat geschrieben:"var" ist die Deklaration, und vergleichbar zu "int" usw in C und Java.
Halt genauso global wie Python-global.Die "undeklarierten" Variablen sind in JS auch nicht wirklich "global", sondern sind Attribute des umgebenden Objektes, sprich im Browser window.
Aber auch nur die Suchewo JS nach nicht-lokalen Variablen sucht kannst du (halbwegs) mit with() steuern:
Code: Alles auswählen
obj = {}
with(obj) { a = 23 }
obj.a // undefined
Ja, aber in diesen, und den meisten anderen Sprachen brauchst du einen Deklarationsbefehl damit es lokal ist.Darii hat geschrieben:Habe ich doch geschrieben.LanX hat geschrieben:"var" ist die Deklaration, und vergleichbar zu "int" usw in C und Java.
Bei Python (und wie wir jetzt wissen Ruby) ist es umgekehrt. Da brauchst/bräuchtest du ein nonlocal.¹
Dieser eine Punkt der dich an JS also nervt, begegnet dir fast überall wieder.
¿oder was hattest du gemeint mit:
?Darii hat geschrieben: Und die umständliche Scoping-Regel, der man zu verdanken hat, dass man vor praktisch jede Variable var schreiben muss.
1) wobei ich jetzt nicht glaube das "nonlocal" in Py selbst eine Deklaration ist, die Variable muss bereits in einem äußeren Scope deklariert worden sein, oder wird damit implizit eine globale Variable deklariert???
@LanX: Der Punkt beim ``var`` begegnet einem nicht überall. Bei welchen Sprachen kann man denn so einfach aus versehen den globalen Namensraum vollmüllen? In C, Java, C#, usw. jedenfalls nicht -- da muss man die Variable auch irgendwo da draussen noch einmal explizit deklarieren, sonst kompiliert es gar nicht erst. Man muss bei JavaScript also immer an das ``var`` denken, denn das ist ja das was man in 99% der Fälle haben will, aber es ist nicht so offensichtlich wenn man es mal vergisst. Weil das trotzdem noch "funktioniert".
Nun das sind alles statisch typisierende Sprachen, wo es natürlich keine "Defaultdeklaration" ohne Keyword geben kann!BlackJack hat geschrieben: In C, Java, C#, usw. jedenfalls nicht --
Was ich meinte ist dass "var" den gleichen Scope erzwingt wie "int".
Ich kenne es schon traditionell von BASIC, das es einen "local"-Befehl gibt, das spiegelt sich auch in den meisten mir bekannten Scriptsprachen wieder. (in Perl steht "my" analog zu "var"¹ für lexikalische Variablen)
Bereits LISP muss man explizit mit "let" lokalisieren, während "set" global ist.
Ergo ist das Verhalten von Python und Ruby² IMHO nicht die Regel.
Dafür das man nicht versehentlich einen globale Variable deklariert kann man üblicherweise eine explizite Deklaration erzwingen (in Perl mit "use strict;")³
Ich denke jslint kann für solche "strictness" in JS benutzt werden.
Darüber welches Verhalten (local vs nonlocal) nun mehr Vorteile hat, will ich mir jetzt kein Urteil anmaßen...
Worauf ich hinaus wollte, dass JS sich so verhält wie die meisten anderen Scriptsprachen, kann man wohl kaum als spezifische Kritik an JS anführen...
1) allerdings global ist bei mir var nicht lexikalisch!
Code: Alles auswählen
javascript: var a=10; alert(window.a)
NACHTRAG:
2) in Ruby ist es tatsächlich nochmal etwas anders, dort gibts einen expliziten Sigil für global vars
http://www.rubyist.net/~slagell/ruby/globalvars.html
3) interessant, ECMA-Script 5 führt auch "use strict" ein...
Zuletzt geändert von LanX am Sonntag 25. Juli 2010, 18:30, insgesamt 2-mal geändert.
@LanX: Wieso kann man das nicht als Kritik an JavaScript anführen? Nur weil Perl genau so dämlich an der Stelle ist, wird's bei JavaScript ja nicht besser. Im Gegenteil -- JavaScript ist wesentlich jünger, da hätte man ja aus den Fehlern lernen können.
BASIC anzuführen ist an der Stelle ein wenig problematisch, weil es das so nicht gibt. Das original BASIC hatte keine Funktionen/Sichtbarkeitsbereiche und in Dialekten wird es wahrscheinlich alle möglichen Semantiken geben.
BASIC anzuführen ist an der Stelle ein wenig problematisch, weil es das so nicht gibt. Das original BASIC hatte keine Funktionen/Sichtbarkeitsbereiche und in Dialekten wird es wahrscheinlich alle möglichen Semantiken geben.
@BlackJack:
ich sagte "spezifische" Kritik an JS!¹
Du kannst natürlich von deinem Py-POV generell alle anderen Sprachen dafür kritisieren, das sie nicht per default lokalisieren (Aber auch diesbzgl war ich deutlich)
NACHTRAG:
1)vielleicht wäre die Wortwahl "JS-spezifische Kritik" deutlicher gewesen.
ich sagte "spezifische" Kritik an JS!¹
Du kannst natürlich von deinem Py-POV generell alle anderen Sprachen dafür kritisieren, das sie nicht per default lokalisieren (Aber auch diesbzgl war ich deutlich)
NACHTRAG:
1)vielleicht wäre die Wortwahl "JS-spezifische Kritik" deutlicher gewesen.