[linux-l] Ruby: sehr cool, aber auch sehr laaaahm... wie geht's schneller?!

Volker Grabsch vog at notjusthosting.com
Mo Aug 28 00:53:53 CEST 2006


On Tue, Aug 22, 2006 at 08:35:04AM +0200, Oliver Bandel wrote:
> > Aber ich persönlich finde die Sprache nicht gut designt.
> > Unter den dynamisch typisierten Sprachen finde ich nach
> > wie vor Python super designt, da könnte höchstens Scheme
> > mithalten (nicht kosmetisch, aber konzeptionell).
> [...]
> 
> Ich kenne von den dynamischen Sprachen bisher nur Perl.
> Python wollte ich mir auch schon lange, lange anschauen,
> aber habe ich halt noch nicht gemacht.
> 
> Ich dachte, daß Ruby das beste aus allen dynamischen Welten
> eingesammelt hat und daher auch best-designed ist...

Python genauso. Na gut, Python hat keine Blöcke, aber dafür
Iterator-Generatoren, was IMHO sogar noch eleganter ist. YMMV

> Ruby kam bei mir so nach "Eierlegender Wollmilchsau" rüber,
> und soll derzeit woohl an Popularität sehr zulegen...

Python *hat* schon diese Popularität.

> ...da dachte ich dann, ist es denn mal Zeit sich das endlich anzuschauen.

Ich kann nur empfehlen, solch eine Sprache sich anzusehen.
Auch ich habe mit Ruby angefangen und dann auch Python
gemacht.

> Hattest Du nicht auch Ruby sehr hervorgehoben bisher?

Ich habe Ruby und Python bisher gleichermaßen hervorgehoben.

Zuerst habe ich mit Ruby begonnen, das viele "kleinere" Dinge
und "was größeres" gemacht. Dabei sind mir etliche Bugs im
mod_ruby des Apache aufgefallen, die auf einem Niveau waren,
dass sich einem die Haare sträuben. Es wurde aber auch unnötig
schwer gemacht.

In Python merkt man, dass die Klassen (insbesondere die gemeinsame
Basisklasse "object") möglichst einfach gehalten sind, und vorallem
dass man zum "Nachbauen" (andere Klasse mit gleichem Interface)
möglichst wenig Methoden braucht. Gerade bei sog. "dateiartigen
Klassen" ("file like objects", Streams) ist das von großem Wert.
Im Design von Ruby findet man keine solche Weitsicht. Im Gegenteil,
es ist sogar möglich (und gängige Praxis), irgendwelchen Basisklassen
im Nachhinein weitere Methoden aufzudrücken ... es geht fast immer
auch eleganter, aber so ist's "pragmatisch" ... dieses Ruby-Schlagwort
hat sich für mich in einen anderen Sinn gedreht, als ich die Schlampig-
keiten bemerkte. Da ist mir der unbarmherzige perfektionistische GvR
wesentlich lieber. ;-)

Außerdem erzeugt Python ganz nebenbei Bytecode (*.pyc) für eine eigene
VM. Ruby macht das auch, aber Python macht es explizit. Auch
"optimierten Bytecode" (*.pyo) kann man erzeugen. Python kann auch
Bytecode für die Java-VM erzeugen (Jython). Auch das zeugt IMHO von
einem besseren Design sowohl der Sprache als auch der Werkzeuge
(Interpreter, etc.), und vorallem von eine größeren, aktiveren
Community.

Und dann die Web-Frameworks. Am bekanntesten für Python sind TurboGears
und Django. Ich finde, TurboGears kann es locker mit Ruby-on-Rails
aufnehmen. Und Django schlägt es IMHO um Längen. Einziger Nachteil
von Django: Unicode-Unterstützung lässt stark zu wünschen übrig. :-(

> > Ich habe viele buggige Ruby-Bibliotheken gefunden,
[...]
> Oh jeh... jetzt nur nicht demotivieren lassen ;-)
> ... nicht daß ich das "jetzt lerne ich Ruby" doch noch hinschmeisse ;-)

Ich mein ja nur, dass du dir danach auf jeden Fall auch noch Python
ansehen solltest. Oder Dylan, obwohl ich zu Dylan nicht viel sagen
kann, außer dass es im CCC einen gewissen Beliebtheits-Grad erreicht
hat.

> > Dir als OCaml-Fan, der mir in Sachen Perfektionismus wahr-
> > scheinlich sehr ähnlich ist, würde ich daher dringend eher
> > zu Python raten.
> 
> Oha... oh jeh ;-(
> 
> Auf's falsche Pferd gesetzt?!
> 
> Naja, egal, dann kommt eben Python nach Ruby dran. ;-)

So seh ich das auch. :-)

> Ich mag bei Ruby z.B. (u.a.) diese awk-ähnlichen Konstrukte,
> wo man einen Block mit { ... } anderen Anweisungen
> gegenüber "assoziiert".

Gut, das ist etwas, das Python in der Form nicht hat. Aber
dafür gibt es Iterator-Generatoren (das "yield"-Kommando).
Das läuft ungefähr so:

    def zaehle123():
        yield 1
        yield 2
        yield 3

    for nr in zaehle123():
        print nr

Das liefert entsprechend:
    1
    2
    3

Der Unterschied zu Ruby: zaehle123() nimmt nicht einfach
eine Funktion (Block, Closure) als Parameter entgegen. Statt-
dessen liefert die Funktion "zaehle123()" beim Aufruf ein
Iterator-Objekt. Im Interpreter sieht das so aus:

>>> i = zaehle123() 
>>> i
<generator object at 0xb7d3c22c>
>>> i.next()
1
>>> i.next()
2
>>> i.next()
3
>>> i.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
StopIteration
>>> 

Das heißt, es sieht nicht nur so aus, sondern der Kontrollfluss
wird *tatsächlich* unterbrochen. Jeder "yield"-Aufruf ruft nicht
einen bestimmten Block auf, sondern er gibt den Kontrollfluss
zurück.

> > Da sucht man sich
> > die *echten* Flaschenhälse raus [...], und optimiert
> > sie, zur Not durch Reimplementierung in C.
> > (Ocaml wäre natürlich cooler, weil etwa genauso schnell,
> > aber robust)
> 
> Wenn man aber z.B. Rzby und OCaml verbinden will,
> dann müsste man da die Brücke via C schlagen.
> Sowohl OCaml als anscheinend auch Ruby sollen
> ja das Einbinden von C-Code einfach machen.
> Wenn man aber beide Welten verbinden will, dann muß man sich
> da via C eine Schnittstelle bauen.
> Wie sowas wohl aussehen würde?!

Gar nicht. Aber Ocaml (oder andere ML-Sprachen) könnten in der
Auto-Industrie oder anderen Robotik-Gebieten sehr interessant
sein. Da gibt es ATM nur C als einzige Alternative zur Maschinen-
Sprache des jeweiligen Mikrorechners. Also wäre ein Ocaml->C
Compiler der Renner. Aber ausgerechnet das ist wohl konzeptuell
ein großes Problem, weil dieser C-Code niemals auch nur an den
Ocaml-Bytecode rankommen würde. (irgendwas bei den Closures
geht das wohl nur extrem unelegant, was man im Assembler ganz
leicht hinkriegt, weil man die Stackframes direkt kontrolliert).

Jedoch gibt das PyPy-Projekt Hoffnung dafür, Python in effizienten
C-Code (für Interpreter-Verhältnisse) zu compilieren. Auch Type-
Inferring wird dort gemacht, d.h. beispielsweise Variablen, bei
denen im Python-Code klar ist, dass sie nur int-Werte enthalten,
werden direkt als "int" bzw. "long int" in C übersetzt.

> [...Performance-Optimierung...]
> > Auf sowas sollte man aber niemals optimieren, weil das
> > bei anderen Interpreter-Implementierungen oder auf anderen
> > Betriebssystemen total anders aussehen kann. Auch zukünftige
> > Implementierungen werden immer auf die gebräuchlichen Muster
> > optimiert werden, sodass gutes, einfaches Design auch in
> > Sachen Performance die besten Zukunfts-Aussichten hat.
> 
> Naja, soooo viele Ruby-Interpreter gibt's ja noch nicht ;-)

Nein, aber es gibt zukünftige Versionen des Interpreters.
Ditto für Python. Und bei langfristigen Sachen *muss* man auf
zukünftige Interpreter-Versionen und (im Moment noch) Beta-
Stadien bauen. Zumindest gilt diese Regel für alle Programmierer,
die ich kenne, die an halbwegs ernsthaften Aufträgen arbeiten.

> > Nun gut, mein Programm
> > war wirklich ein Paradebeispiel für etwas, wo mir ein gutes
> > Typsystem sehr entgegen kommt, und die uralte Implementierung
> > war in C++, aber dennoch hat es mich positiv überrascht, wie
> > einfach und "straight forward" ich voran gekommen bin.
> 
> Oha... hast Du hauptsächlich imperativ bzw. OO-like programmiert,
> oder auch funktionale Ansätze verstärkt genutzt?

Funktionale Ansätze habe ich auf jeden Fall genutzt. Spätestens
dann, wenn dieser Stil einfach mal das gegebene Problem direkt
löst.

Aber bei sehr vielen "Mustern" ist es relativ egal, ob man sie
im OO-Stil oder im funktionalen Stil löst. Da ist es dann die
Sprache, die Ausschlag gibt, welcher Stil im konkreten Fall
leichter/natürlicher/direkter umsetzbar ist.

Genauso wie Ocaml eine funktionale Sprache ist, in der man auch
OO programmieren kann, sind Ruby/Python nunmal OO-Sprachen, in
denen man auch funktional programmieren kann.

Meinen ersten "harten" Paradigmen-Wechsel hatte ich übrigens
mit Prolog. Da habe ich auch gelernt, die ätzend es sein kann,
keine Schleifen zu haben und *auf Biegen und Brechen* Rekursionen
verwenden zu müssen. Andererseits ist natürlich die automatische
Beweisführung in Prolog einfach mal genial, und spart bei ent-
sprechenden Problemen sehr viel Entwicklungszeit.

> > im Gegenteil: Ich
> > verwende den Compiler, um meinen Programmier-Stil zu
> > verbessern. Wie? Indem ich "-w A" mache, also alle Warnungen
> > an. Dann kann selbst ein Pedant noch was vom Compiler lernen.
> > Eine zusätzliche Warnung, sie klang total belanglos, war
> > aber bei genauerem Nachdenken wirklich berechtigt, und hat
> > mich auf etwas aufmerksam gemacht, dass ich vorher zu wenig
> > beachtet hatte.
> 
> Was für Warnungen waren das (oder was für eine war das, Du hast da wohl
> eine spezielle im Sinn?!).

Den Code musste ich erstmal wieder reproduzieren ... so, fertig.
Ein einfaches Beispiel, das die Sache ungefähr trifft:

    type sign = POS | NEG

    let f = function
        | _, POS when 1 = 1 -> 0
        | _, NEG -> 1
        | _ -> 2
    ;;

Wenn du das durch "ocaml -w A ..." jagst, kommt folgende Warnung:

    line 6, characters 6-7:
    Warning E: this pattern is fragile. It would hide
    the addition of new constructors to the data types it matches.

Es hat ein Weilchen gedauert, bis ich das geschnallt habe. Aber dann
wurde mir klar, wo der Hase im Pfeffer liegt. Nicht übel, da hab ich
wirklich gestaunt.

Mein realer Code sah natürlich ein wenig anders aus, aber den krieg
ich nicht mehr zusammen. Ich habe ihn nämlich sowieso gegen was
Eleganteres ersetzt gehabt. Aber frag mich nicht mehr, was das genau
war. Es passierte in einer sehr frühen Anfangsphase des Programmes.


> ===================================================================
>   File "reader.py", line 1
>     import sys
>     ^
> SyntaxError: invalid syntax
> ===================================================================
> 
> Was nu?
> 
> "Ich nix Python!" (jedenfalls noch nicht)

Hab ich schon erwähnt, dass Python die Einrückung beachtet. Also bitte
all meine Beispiele um 4 Leerzeichen ausrücken. Danke. :-)


Viele Grüße,

    Volker

-- 
Volker Grabsch
---<<(())>>---
Administrator
NotJustHosting GbR



Mehr Informationen über die Mailingliste linux-l