Wieso Blöcke keine echten Funktionen sein sollten

written by Martin Häcker on

Zu "Ergie" von Rainer von Vielen

In meiner Freizeit beschäftige ich mich gerade viel mit Ruby - sowohl The Ruby Way, als auch The Ruby Programming Language sind dafür gute Bücher.

Und ich muss sagen, das Ruby ist nicht unspannend. Zwar gibt es auch einiges dass ich ganz schön eklig finde (z.B. das Flip-Flop Statement, oder dass so viel mit globalen Variablen gearbeitet wird, oder dass viele Sachen so komplex sind.

Aber darum gehts hier gar nicht. Mir geht es hier um die Erkenntnis wieso und unter welchen umständen man Blöcke als etwas anderes sehen möchte als anonyme Funktionen.

Das dauert nämlich bis man das merkt.

Zuerst einmal die Konfusion: Ruby hat eine Syntax für Methoden

def method(positional_argument, *all_other_arguments)
  # some body
end

und eine für Blöcke

10.times do |positonal_argument, *all_other_arguments|
  # some body
end

Wieso der Unterschied? Wieso macht man Blöcke nicht einfach zu normalen Funktionen die man dann auch gleich mit () aufrufen kann anstatt immer ein a_block.call() verwenden zu müssen?

Echte Lambdas gibt es ja noch zusätzlich in Ruby.

Well, den Unterschied in der Syntax verstehe ich immer noch nicht. Aber dahinter steht der Grund dass Blöcke eine andere Aufgabe haben als Methoden - der Punkt ist nämlich dass man sie gerne als Teil der sie lexikalisch umgebenden Methode betrachten möchte damit man sie nutzen kann um mit ihnen Kontrollstrukturen zu implementieren. Hier mal ein Beispiel:

def find(needle, haystack)
  haystack.each.with_index do |index, element|
    if element == needle
      return index
    end
  end
  return nil
end

(Also als Python Programmierer muss ich ja sagen dass die end statements ganz schön auf die Nerven gehen. Doppelte Zeilenanzahl für null zusätzliche Information oder Nützlichkeit. But I digress.)

Das spannende daran ist die Zeile return index. Seht ihr was daran besonders ist? Ich Puzzle es mal auseinander als wäre der Block eine funktion, dann wird es klar.

find ruft einen iterator auf dem haystack auf, d.h. übergibt ihm eine Funktion die das richtige Element findet. Diese Funktion erhällt ein Element aus dem haystack und einen index und gibt diesen index zurück wenn das element das gesuchte ist.

Und da ist das Problem: Damit find funktioniert muss return index find verlassen und nicht nur die iterator-funktion.

Das ist der Grund wieso man Blöcke als etwas anderes als Funktionen/Methoden betrachten muss wenn man sie nutzen will um damit Kontrollstrukturen implementieren zu können und ihre volle Nützlichkeit für Abstraktionen verwenden zu können.