2
scala> val alist = List(1,2,3,4,5)
alist: List[Int] = List(1, 2, 3, 4, 5)

scala> alist filter { 2.< }
res2: List[Int] = List(3, 4, 5)

scala> alist filter { 2 < }
res3: List[Int] = List(3, 4, 5)

scala> alist filter { > 3 }
<console>:1: error: ';' expected but integer literal found.
       alist filter { > 3 }

Why would { 2.< } and {2 <} work? I think at least I should write { 2 < _ } right?

A method that requires no arguments, you can alternatively leave off the dot and use postfix operator notation:

scala> val s = "Hello, world!"
s: java.lang.String = Hello, world!
scala> s toLowerCase
res4: java.lang.String = hello, world!

But here, < method is not those kinds of methods which requires no arguments right?

Can you point me what is this usage?

Sawyer
  • 15,581
  • 27
  • 88
  • 124
  • possible duplicate of [Concise notation for single arg anonymous function (avoiding underscore) not working as expected](http://stackoverflow.com/questions/6593277/concise-notation-for-single-arg-anonymous-function-avoiding-underscore-not-wor) – om-nom-nom Feb 24 '12 at 07:09
  • I don't think it's a duplicate. The linked question is about different syntax options for functions, this one is turned the other way round, resulting in the given syntax error. – Frank Feb 24 '12 at 08:05

3 Answers3

2

The reason for this is that 2 is an object, so if you write 2.< or 2 < (which are actually the same in Scala), then you are calling a method < on the object 2.

If you just write < or > the compiler will look for such a method in the local scope, but won't find one. Similarly, writing > 3, the compiler needs a method > available, which isn't.

You can also see this behavior in the console directly:

scala> 3.<
<console>:8: error: ambiguous reference to overloaded definition,
both method < in class Double of type (x: Char)Boolean
and  method < in class Double of type (x: Short)Boolean
match expected type ?
               3.<
                 ^

As you can see, there are several implicts defined, which turn 3 into an object of a class that defines a < method. So this works in principal, but cannot stand on its own. It works, however, if you have more type information like in your example.

Contrast this with the following:

scala> <(3)
<console>:8: error: not found: value <
              <(3)
              ^

Here you can see the compiler looking for a standalone < somewhere. Note that the error message says value, but this still means it could be a function, as the value type may be (Int, Int) => Boolean or something like that.

Frank
  • 10,461
  • 2
  • 31
  • 46
  • So why you can call a method with no argument like `2.<` and why this is equivalent to `2 <` ? any where address this usage formally? Why I cannot call my method with empty arguments? – Sawyer Feb 24 '12 at 08:25
  • in this context scala allow you to write `(x: Int) => 2 < x`, `x => 2.<(x)`, `2.<(_)`, `2 < _`, `2.<` or just `2 <`. In all this cases scala will create anonymous __function__ of type `Int => Boolean`, which will invoke __method__ `<` when called. – incrop Feb 24 '12 at 08:46
  • @incrop, your link in the other post does answer why the `_` can be omitted, but the `2.<` syntax is inconsistent with the syntax rule. If you can call a method like this, it means it doesn't have any arguments, and it does not produce and side effects, like s.toString, unless I can see this usage is address officially in somewhere. – Sawyer Feb 24 '12 at 09:06
  • 1
    The rules that applied here are explained in §6.26.2 (Method Conversions) and §6.26.5 (Eta Expansion) of scala reference. – incrop Feb 24 '12 at 09:32
1

What is happening is an Eta Expansion (6.26.5):

Eta-expansion converts an expression of method type to an equivalent expression of function type.

In this case, 2 < is a method type: (one of) the method < on Int. However, filter expects a function type. In such a case, Scala does automatic eta expansion.

Note that, because the type expected by filter is known, it can correctly infer what 2 < method is being called.

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
1

2.< refers to the method < of object 2, whereas 2.<(_) returns a new function with one argument. The latter is a shortcut for (is expanded to) (x: Int) => 2 < x where the type Int was inferred by the scala compiler from the type of the elements of alist.

> 3 in your case does not refer to any method or object of any object. > is a legal scala identifier (for a method, function or object), but 3 is not a legal identifier (it begins with a digit). > a could be a reference a member a of object > (>.a). But neither of those exist in your example. _ > 3 however returns a new function with one argument, which you could also write (x: Int) => x > 3.

This is in essence the same than Daniel C. Sobral's answer and incrop's comment to Frank's answer, but less formal and with more examples. Hope this helps get an intuition.

Julien Gaugaz
  • 321
  • 3
  • 10