3

I'm having the hardest time understanding when I can or can't omit brackets and/or periods, and how this interplays with _.

The specific case I had with this was

val x: X = ???
val xss: List[List[X]] = ???
xss map x :: _ //this doesn't compile
xss map _.::(x) //this is the same as the above (and thus doesn't compile)

the above two seem to be identical to xss.map(_).::(x)

xss map (x :: _) //this works as expected
xss map {x :: _} //this does the same thing as the above

meanwhile, the following also fail:

xss.map xs => x :: xs //';' expected but '=>' found.
xss.map x :: _ //missing arguments for method map in class List; follow this method with `_' if you want to treat it as a partially applied function
//so when I try following the method with _, I get my favourite:
xss.map _ x :: _ //Cannot construct a collection of type That with elements of type B based on a collection of type List[List[Main.X]]
//as opposed to
xss map _ x :: _ //missing parameter type for expanded function ((x$1) => xss.map(x$1).x(($colon$colon: (() => <empty>))))

Right now, I often play "toggle the symbols until it compiles" which I believe to be a suboptimal programming strategy. How does this all work?

Nader Ghanbari
  • 4,120
  • 1
  • 23
  • 26
Martijn
  • 11,964
  • 12
  • 50
  • 96
  • 2
    Did you see http://stackoverflow.com/questions/2173373/scala-foreach-strange-behaviour? – kiritsuku Oct 18 '14 at 11:15
  • Not yet, thank you. Looking. – Martijn Oct 18 '14 at 11:18
  • 1
    This should help with the problem of where to leave out parentheses/dots: http://stackoverflow.com/questions/1181533/what-are-the-precise-rules-for-when-you-can-omit-parenthesis-dots-braces-f – kiritsuku Oct 18 '14 at 11:23

1 Answers1

2

First we need to distinguish between xss.map(f) and xss map f. According to Scala Documentation any method which takes a single parameter can be used as an infix operator.

Actually map method in List is one of these methods. Ignoring the full signature and the fact that it's inherited from TraversableLike, the signature is as follows:

final def map[B](f: (A) ⇒ B): List[B]

So it takes a single parameter, namely f, which is a function with type A => B. So if you have a function value defined as

val mySize = (xs:List[Int]) => xs.size

you can choose between

xss.map(mySize)

or

xss map mySize

This is a matter of preference but according to Scala Style Guide, for this case, the latter is preferred, unless if it is part of a complex expression where it's better to stick with dot notation.

Note that if you opt to use the dot notation you always need to qualify the function application with brackets! That's why none of the following compiles successfully.

xss.map xs => x :: xs // Won't compile
xss.map x :: _ // Won't compile
xss.map _ x :: _ // Won't compile

But most of the time instead of passing a function value you need to pass a function literal (aka anonymous function). In this case again if you use the dot notation you need something like xss.map(_.size). But if you use the infix notation, it will be a matter of precedence.

For example

xss map x :: _ // Won't compile!

does not work because of operator precedence. So you need to use brackets to disambiguiate the situation for compiler by xss map (x :: _).

Use of curly braces instead of brackets has a very clear and simple rule. Again any function which takes only one parameter can be applied with curly braces instead of brackets, both for infix and dot notations. So the following statements will compile.

xss.map{x :: _}
xss map {x :: _}

For avoiding confusions you can begin with dot notation and explicit types for parameters. Later after being compiled - and probably writing some unit tests for your code - you can start refactoring the code by removing unnecessary types, using infix notation, and using curly braces instead of brackets where it makes sense.

For this purpose you can refer to Scala Style Guide and Martin Odersky's talk in Scala Days 2013 which is concerning Scala coding style. Also you can always ask for help from IDEs for refactoring the code to be more concise.

Nader Ghanbari
  • 4,120
  • 1
  • 23
  • 26
  • great answer, thank you. As far as asking the Eclipse plugin to refactor my code - in my experience that ends badly, though I head good things about intellij – Martijn Oct 19 '14 at 11:17
  • I have a great time with [IntelliJ IDEA Scala Plugin](http://plugins.jetbrains.com/plugin/?id=1347). It automatically detects parts of the code which could be simpler. For example if you write `xss map (mySize)` it will suggest to remove the round brackets. Even if you write `xss map (mySize(_))` it suggests first to remove the unnecessary `_` and then after removing that it suggests to remove brackets. It's smart enough to detect most of the common issues and code smells. – Nader Ghanbari Oct 19 '14 at 11:23