Reputation: 2073
I am currently trying to understand a problem with recursion. This code checks to see if a node is a leaf node, if it is it will increment the amount of leaf nodes.
I can't understand what the fn.call(this) does and then how it then calls the closure inside the for loop.
Here is my code.
class TreeNode {
String name
List<TreeNode> children = []
// if no children, there is no leaf node
boolean isLeaf() {
return !children
}
void walkTree(Closure fn) {
fn.call(this)
for (child in children) {
child.walkTree(fn)
}
}
}
testTreeNode = new TreeNode(name: "Fred", children: [
new TreeNode(name: "Janet", children: [
new TreeNode(name: "Mark"),
new TreeNode(name: "Anne", children: [new TreeNode(name: "Simon") ]),
new TreeNode(name: "Kelly")
]),
new TreeNode(name: "Nigel")
])
def leafCount = 0
testTreeNode.walkTree { node -> if (node.leaf) leafCount++}
Upvotes: 0
Views: 785
Reputation: 519
I hope I'm following correctly, but it seems you have 2 questions:
1. What does fn.call(this)
do?
Firstly, a Closure is an anonymous block of code that can be executed at a later time.
When you call testTreeNode.walkTree
, you are passing the Closure (block of anonymous code) node -> if (node.leaf) leafCount++
as a parameter of the walkTree
method, so that closure becomes the variable named fn
within the context of walkTree
.
Within the walkTree
method, the Closure (block of code) is then being explicitly invoked using the Closure.call(args) method.
See: http://groovy-lang.org/closures.html#_calling_a_closure
2. How is the closure executed inside the for loop?
As the closure can be referred to using the fn
variable name, you are then able to pass that as an argument directly to walkTree
for each child TreeNode in the loop, which then invokes that closure using fn.call(this)
.
If we substitute the Closure usage with the block of code passed, it might be clearer what is happening:
void walkTree(Closure fn) {
//Closure executed here
if (this.leaf) leafCount++
for (child in children) {
//closure passed as argument to walkTree method of child TreeNodes
child.walkTree { node -> if (node.leaf) leafCount++ }
}
}
Upvotes: 5