How to set do-nothing handler for by-name parameter?

I have defined a treeNode method for creating a node and which can have child nodes. Simplified code:

 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 leaf nodes that have no children, but they should have an empty block {} .

Is it possible to specify the children: => Any default do-nothing value, which I can write as:

 treeNode("aaa") { treeNode("bbb") treeNode("ccc") } 

Help ~

+4
source share
2 answers

The problem is not that you cannot give it a do-nothing (default) value; the problem is that even if you do this, functions with multiple parameter blocks must have at least brackets or curly braces for each block.

There is one exception: for an implicit parameter block, you do not need to reference it at all. Unfortunately, you are not allowed to have implicit parameters "by name", and even if you were, your signature would allow any random implicit to work in this place!

Now there is a way around this, which I will show for completeness, but I suggest (provided that you do not just need a different name, for example leafNode ), you just leave {} .

You can get exactly the syntax you want if you follow these steps. First, you need an implicit parameter, but you make it a wrapper class (you can use Function0 , which already exists, but then the next step may 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 by name Any into your new trait, and you need to have an implicit "nothing" available to anyone. 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 restore the behavior that you performed after:

 scala> treeNode("Hi") res1: (String, Any) = (Hi,()) scala> treeNode("Hi") { treeNode("there") } res2: (String, Any) = (Hi,(there,())) 

(in your example, you are not returning anything, here I am to show that it works.)

This is just a lot to avoid some {} s, so I suggest only doing this if you expect it to be very heavily used by DSL, and that the two names are unacceptable. (Also, if you expect it to be very heavily used, treeNode is likely to be long as a name, I would suggest just node .)

+9
source

AFAICT, you cannot pass an empty pool by default.

Btw, you could just split the task based on your treeNode function by creating another def leaf(text:String) = treeNode(t) {}

+6
source

Source: https://habr.com/ru/post/1389873/


All Articles