Die Frage ist inspiriert von diesem .
Proc::new
hat eine Option, die ohne einen Block innerhalb einer Methode aufgerufen werden kann:
Proc::new
darf ohne einen Block nur innerhalb einer Methode mit angehängtem Block aufgerufen werden. In diesem Fall wird dieser Block in das ObjektProc
konvertiert.
Wenn die Instanz proc
/ lambda
als Codeblock übergeben wird, wird die neue Instanz von Proc
erstellt:
Wie man sehen kann, ist weder der Aufruf von Proc::new
noch Proc#initialize
und / oder Proc#call
aufgerufen worden.
Die Frage ist: wie Ruby einen Block Wrapper unter der Haube erstellt und ausführt?
NB Testen Sie den obigen Code nicht in pry
/ irb
console: Sie wissen, dass sie Fehler bei der puren Ausführung haben, im Grunde, weil sie Patches proced.
Es gibt einige Diskussionen über dieses Verhalten im Ruby Issue Tracker, siehe Feature # 10499: Eliminiere implizite Magie in Proc.new
und Kernel#proc
.
Dies ist ein Implementierungsartefakt von YARV: YARV schiebt einen Block auf den globalen VM-Stack und Proc::new
erstellt einfach einen Proc
vom obersten Block auf dem Stack. Also, wenn Sie Proc.new
aus einer Methode heraus aufrufen, die mit einem Block aufgerufen wurde, greift es gerne den Block, der sich oben auf dem Stapel befindet, ohne zu überprüfen, woher er kommt. Irgendwie, irgendwo im Nebel der Zeit, wurde dieses (zufällige) Artefakt (ich würde es eigentlich eher einen Fehler nennen) zu einem dokumentierten Feature. Ein Feature, das die Entwickler von JRuby (und vermutlich Rubinius, Opal, MagLev, etc.) lieber loswerden würden.
Da die meisten anderen Implementierungen völlig anders funktionieren, macht dieses Verhalten, das "kostenlos" auf YARV kommt, sowohl Blöcke als auch% auf andere Implementierungen teurer und verbietet mögliche Optimierungen (was auf YARV nicht schadet, weil YARV optimiert nicht).
Tags und Links ruby lambda metaprogramming proc