I defined a method treeNode
to create a node, and which can have children nodes. The simplified code is:
def treeNode(text:String) (children: => Any) {
val b = new TreeNode(text)
children
}
When I use this method, I have to write:
treeNode("aaa") {
treeNode("bbb") {}
treeNode("ccc") {}
}
You can see the leaf nodes they don't have children, but they have to have a empty block {}
.
Is there any way to give the parameter children: => Any
a default do-nothing value, that I can write the code as:
treeNode("aaa") {
treeNode("bbb")
treeNode("ccc")
}
Help~
The problem is not that you can't give it a do-nothing (default) value; the problem is that even if you do, functions with multiple parameter blocks have to at least have parentheses or braces for each block.
There is one exception: an implicit parameter block does not need to be referenced at all. Unfortunately, you're not allowed to have call-by-name implicit parameters, and even if you were, your signature would allow any random implicit to work in that spot!
Now, there is a way around this, which I will show for completeness, but I suggest that (assuming you don't just want another name, like leafNode
) you just leave the trailing {}
there.
You can get exactly the syntax that you want if you do the following. First, you need an implicit parameter, but you make it a wrapper class (could use Function0
which already exists, but then the next step might have unintended consequences):
trait AnyByName { def eval: Any }
def treeNode(text: String)(implicit children: AnyByName) = (text,children.eval)
Now you need two things--you need to be able to convert a by-name Any
into your new trait, and you need to have an implicit do-nothing one available. So we
implicit val nameForDoingNothing = new AnyByName { def eval = () }
implicit def wrap_any_by_name(a: => Any) = new AnyByName { def eval = a }
And now we recover the behavior that you were after:
scala> treeNode("Hi")
res1: (String, Any) = (Hi,())
scala> treeNode("Hi") { treeNode("there") }
res2: (String, Any) = (Hi,(there,()))
(in your example, you don't return anything; here I do, to show that it works.)
It's a lot of tooling just to avoid some {}
s, though, which is why I'd suggest only doing this if you anticipate this to be a very heavily used DSL and that two names is unacceptable. (Also, if you expect it to be very heavily used, treeNode
is probably painfully long as a name; I'd suggest just node
.)