Make "fewerBraces" available outside snapshot releases

OK, I think we are converging on 15273 as the solution. It’s the most conservative alternative in any case. In that spirit, I think we should also try to avoid situations where the “:” looks like line noise. Examples to avoid:

    xs.groupMap:
      x => x * x
    :
      x => x.toString

or

    m.size > 0 && :
      val firsts = m(0)
      firsts.length > 0

To that purpose, I propose a simple and quite restrictive lexical rule: A “:” can only start an indented block or lambda if it follows an identifier, a ")" or a “]” with no intervening whitespace between the two tokens. That will rule out the two uses above and would also prevent a few fancy DSLs that I can see coming otherwise.

Does it mean that I have to use braces for curried blocks and blocks as operands? Not necessarily. We can use indentation by adding explicit function names. In the first case:

    xs.groupMap:
      x => x * x
    .apply:
      x => x.toString

That works today. It’s currently not as efficient as two inline arguments since it performs an eta expansion of the part before the .apply. But we can fix this in the compiler with a peephole optimization.

In the second case, we can write:

   m.size > 0 && nested:
     val firsts = m(0)
     firsts.length > 0

nested would be an inline function defined like this:

    transparent inline def nested[T](inline x: T): T = x

We could also use locally, which exists today, but that one is not inline, so unlike nested it does leave a footprint in the code. I find nested a better name than locally, so we might want to add that to Predef and deprecate locally at some point.

But of course, it’s also fine to keep using braces in both of these cases. It’s just that if the tendency is at some point to avoid braces everywhere, there is a way to achieve that.

3 Likes