This usage of underscore is known as Placeholder Syntax for Anonymous Functions:
Such an expression represents an anonymous function where subsequent
occurrences of underscores denote successive parameters.
Note each underscore refers to different parameter so for example
_ + _
expands to
(x1, x2) => x1 + x2
Also expression _ + _
makes use of point-free syntax as opposed to
_.+(_)
for example
List("Steve", "Tom", "John", "Bob").reduce((x1: String, x2: String) => x1.+(x2)) // : String = "SteveTomJohnBob"
List("Steve", "Tom", "John", "Bob").reduce((x1, x2) => x1.+(x2)) // : String = "SteveTomJohnBob"
List("Steve", "Tom", "John", "Bob").reduce(_.+(_)) // : String = "SteveTomJohnBob"
List("Steve", "Tom", "John", "Bob").reduce(_ + _) // : String = "SteveTomJohnBob"
so now it should be clearer why expression _.compareTo(_) < 0
works
List("Steve", "Tom", "John", "Bob").sortWith(_.compareTo(_) < 0) // : List[String] = List("Bob", "John", "Steve", "Tom")
List("Steve", "Tom", "John", "Bob").sortWith((x1, x2) => x1.compareTo(x2) < 0) // : List[String] = List("Bob", "John", "Steve", "Tom")
Another way to see this let's type-ascribe the sugared expression
scala> (_.compareTo(_) < 0): ((String, String) => Boolean)
val res0: (String, String) => Boolean = $Lambda$7865/418832725@18987bf5