I very heavily use - some say overuse - block initializations and block scoped methods (primarily methods within methods). Generally, my rule of the thumb is to put everything in as narrow scope as possible, which sometimes results in those nested definitions taking a considerable amount of space. This results in code akin to:
val myField = {
def initializer() :Int = {
...
}
initializer()
}
In such cases, I’d much rather write
val myField = {
initializer()
def initializer() :Int = {
}
}
Local methods can already call methods defined after them in the same scope.
I can’t, however, because the type of the above block is Unit
. This is a degenerate example, so the case isn’t as pronounced, but with several helper methods and the actual initializing expression being something more than calling one of them, it really hinders readability. I sometimes resort to code as in the first example, with an artificial initializer
method to bring the actual initializing expression closer to the field declaration, but that could be also argued as being just additional noise, especially as the reader can only trust
that the initializer
method is called only once, at the end of the block.
I thus wonder if it wouldn’t be better if, when determining the type of a block expression, all def
declarations were ignored. It would also help catch bugs such as code in the second example, were the type of the whole expression is inferred to be Unit
because of a def
.
- Is there a good reason for why the things are as they are, or couldn’t be as proposed here?
- Do you think it would actually be a change for the better?