Code mit eval ausführen ist auf jeden Fall (sehr sehr viel) langsamer, da der Code erst geparst werden muss. ALLERDINGS eine Methode einmalig mit eval definieren und sie hinterher häufig ausführen geht wiederum schneller als Procs auszuführen.
Aber The_Burrito hat Recht: Der Verwendungszweck ist ein anderer. Procs sind deshalb langsamer als nativ definierte Methoden, weil sie mehr können als Methoden. Procs binden den umliegenden Kontext und können auf alle Variablen und Methoden zugreifen, auf die du im Scope Zugriff hattest. Das bedeutet das Procs sehr viel mächtiger sind als eval.
Mal ein, zugegebenermaßen etwas sinnfreies, Beispiel:
Angenommen get_block würde einen String "@x + y" zurückgeben, so würde es zu einem Fehler führen. Denn sobald du den String außerhalb von Foo aufrufst sind die Variablen @x nicht mehr vorhanden. Ja außerhalb von get_block ist nicht einmal die Variable y mehr vorhanden. Nun könntest du natürlich folgendes machen:
Das geht aber nur wenn du lediglich lesenden Zugriff auf die Variablen haben willst. Was ist aber, wenn du in deinem Code die Instanzvariable @x ändern willst? Das geht wirklich nur über Procs. Eval-Strings können das nicht. Sie könnten höchstens von außen auf das Foo Objekt zugreifen, oder aber über eine andere Methode innerhalb des Foo-Objekts evaluiert werden (z.B. mit instance_eval). Beides ist aber nur möglich wenn du Zugriff auf das Foo-Objekt hast. Das wiederum bedeutet du musst die Referenz auf das Foo Objekt die ganze Zeit mitschleppen, oder aber in einer globalen Variable speichern (*urks*).
Procs sind gerade durch ihre Eigenschaft, in ihrem Scope Variablen zu lesen und zu ändern, sehr mächtig und können dadurch für vielerlei Zwecke eingesetzt werden, wo eval nicht so leicht möglich ist. Ein Beispiel wo die RGSS Procs einsetzt: Wenn du eine Message anzeigst wird der Interpreter in einen Haltezustand gesetzt (damit er die nächste Zeile Eventcode erst ausführt, wenn du die Message weggeklickt hast). Damit der Interpreter aber aus diesem Haltezustand wieder hinauskommt, wird ein Proc gesetzt der ausgeführt werden soll, sobald die Message weggeklickt wurde, und der den Haltezustand vom Interpreter wieder entfernt. Wie hätte man das anders lösen können? Nun, man hätte den Haltezustand als öffentliches Attribut definieren müssen und den Interpreter global abspeichern müssen, damit bekannt ist welcher Interpreter gerade die Message anzeigt (es können ja mehrere parallele Interpreter aktiv sein, aber nur einer zeigt gerade die Message an). Das wäre nicht einmal eine besonders schlechte Alternative. Hier einen Proc zu benutzen ist okay, aber nicht zwingend notwendig. Wichtig ist aber: Du hättest hier keinen eval-String als Ersatz nutzen können. Denn die grundlegende Eigenschaft, den Haltezustand innerhalb des Interpreters ändern zu können, hat nur ein Proc, nicht aber ein eval-String.
Zudem musst du bedenken: eval-Strings werden erst auf ihre Syntax geprüft, wenn sie evaluiert werden. Procs sind Teil des Programmcodes und werden sofort geprüft. Du kannst also auf diese Weise Syntaxfehler erzeugen, die erst sehr spät (oder womöglich gar nicht) zum Absturz führen. Weiterhin sind evals in der Lage Code zu konstruieren. Procs können das nicht, hier musst du andere Techniken anwenden. D.h. du könntest z.B. den Script-Befehl des Makers gar nicht anders als über eval lösen (sinnvoll wäre höchstens noch gewesen die Script-Befehle in einzelne Methoden zu evaluieren, so dass sie nicht jedes Mal erneut evaluiert werden müssen). Gleichzeitig entstehen so aber unter Umständen auch Sicherheitslecks. Angenommen du willst den Namen des Spielerheldens als Variable innerhalb des evals ansprechen, dann kann der Nutzer durch einen fies gewählten Heldennamen jeden beliebigen Code in dein Programm einhacken. Solange dein Programm unverschlüsselt ist, mag das nur ein einfacher Trick sein um Cheats anzuwenden. Wenn du dein Programm verschlüsselst um z.B. deine Grafiken nicht zugänglich zu machen, dann ist das ein einfacher Weg um die Verschlüsselung zu knacken.
Zu guter letzt noch: eval ist unsauber, weil es für viele Probleme eine auf den ersten Blick einfache Lösung bietet. Dabei kommen teilweise aber ziemlich bescheuerte Problemlösungen raus. Mein Lieblingsbeispiel ist von Dubealex. Der hat in einem seiner Scripte folgenden Schwachsinn geschrieben (kein Zitat, sondern nur sinngemäß nachgeschrieben):
Tja, wie hätte man das sinnvoller lösen können? Genau, über einen Array ^^° Deswegen: Bevor man eval einsetzt, lieber erstmal überlegen ob man es wirklich braucht. Ich setze bisher eval nur für Metaprogrammierung ein (um Methoden automatisch generieren zu lassen). Dafür gibt es zwar auch elegantere Lösungen, z.B. über define_method, welches einen Proc in eine Methode umwandelt. Aber wie bereits gesagt: über eval erzeugte Methoden sind genauso schnell wie nativ geschriebene Methoden. Bei Procs ist das nicht der Fall. Die sind langsamer, weil sie den umliegenden Scope binden und damit mächtiger als Methoden sind.