Scala's "postfix ops"
Solution 1:
It allows you to use operator syntax in postfix position. For example
List(1,2,3) tail
rather than
List(1,2,3).tail
In this harmless example it is not a problem, but it can lead to ambiguities. This will not compile:
val appender:List[Int] => List[Int] = List(1,2,3) ::: //add ; here
List(3,4,5).foreach {println}
And the error message is not very helpful:
value ::: is not a member of Unit
It tries to call the :::
method on the result of the foreach
call, which is of type Unit
. This is likely not what the programmer intended. To get the correct result, you need to insert a semicolon after the first line.
Solution 2:
The simplest answer ever:
Dropping dot from methods without parameters is DEPRECATED!
List(1,2,3) reverse //is bad style and will lead to unpredicted behaviour
List(1,2,3) map(_*2) reverse //bad too, because reverse can take first method call from the next line (details below)
OK to drop dot in methods that take one parameter of higher order function like map, filter, count and be safe! Also, purely functional methods like zip.
List(1,2,3) map(_*2) filter(_>2)
(List(1,2,3) map(_*2)).reverse //safe and good
List(1,3,5) zip List(2,4,6)
Long answer WHY
case class MyBool(x: Boolean) {
def !!! = MyBool(!x) //postfix
def or(other: MyBool): MyBool = if(x) other else this //infix
def justMethod0() = this //method with empty parameters
def justMethod2(a: MyBool, b: MyBool) = this //method with two or more
override def toString = if(x) "true" else "false"
}
1) Postfix operator - is actually a method call with no parameters (a!==a.!) and without brackets. (considered not safe and deprecated)
val b1 = MyBool(false) !!!
List(1,2,3) head
2) Postfix operator is method, that should end the line, or else it will be treated as infix.
val b1 = MyBool(true) no! no! //ERROR
//is actually parsed like
val b2 = MyBool(true).no!(no!) //(no!) is unknown identifier
//as bad as
Vector(1,2,3) toList map(_*2) //ERROR
3) Infix operator is method with one parameter, that can be called without dot and parentheses. Only for purely functional methods
val c1 = MyBool(true) or b1 or MyBool(true)
val c2 = MyBool(true).or(b1).or(MyBool(true))
c1 == c2
4) Method with one or more parameters will chain without dot if you call it with parameters. def a(), def a(x), def a(x,y) But you should do this only for methods that use higher order function as parameter!
val d1 = MyBool(true) justMethod2(b1, c1) or b1 justMethod0() justMethod2(c1, b1)
//yes, it works, but it may be confusing idea
val d2 = MyBool(true).justMethod2(b1,c1).or(b1).justMethod0().justMethod2(c1, b1)
d1 == d2
//looks familiar? This is where it should be used:
List(1,2,3) filter(_>1) map(_*2)
Sample warnings:
warning: there were 1 deprecation warning(s); re-run with -deprecation for details warning: postfix operator tail should be enabled by making the implicit value scala.language.postfixOps visible. This can be achieved by adding the import clause 'import scala.language.postfixOps' or by setting the compiler option -language:postfixOps. See the Scala docs for value scala.language.postfixOps for a discussion why the feature should be explicitly enabled.
Solution 3:
It refers to the ability to call a nullary (with no arg list or empty arg list) method as a postfix operator:
By example:
case class MyBool(value: Boolean) {
def negated = new MyBool(!value)
}
val b1 = MyBool( true )
val b2 = b1 negated // Same as b1.negated
See: http://www.scala-lang.org/node/118