Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala's "postfix ops"

I've searched for a half-hour, and still cannot figure it out.

In SIP: Modularizing Language Features there are a number of features which will require explicit "enabling" in Scala 2.10 (import language.feature). Amongst them there is postfixOps, to which I just cannot find a reference anywhere. What exactly does this feature allow?

like image 647
dmitry Avatar asked Oct 22 '12 12:10

dmitry


3 Answers

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.

like image 146
Kim Stebel Avatar answered Sep 22 '22 09:09

Kim Stebel


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.

like image 36
Alex Avatar answered Sep 21 '22 09:09

Alex


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

like image 5
Régis Jean-Gilles Avatar answered Sep 20 '22 09:09

Régis Jean-Gilles