Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use parenthesis in Scala infix notation

When programming in Scala, I do more and more functional stuff. However, when using infix notation it is hard to tell when you need parenthesis and when you don't.

For example the following piece of code:

def caesar(k:Int)(c:Char) = c match {
    case c if c isLower => ('a'+((c-'a'+k)%26)).toChar
    case c if c isUpper => ('A'+((c-'A'+k)%26)).toChar
    case _ => c
}

def encrypt(file:String,k:Int) = (fromFile(file) mkString) map caesar(k)_

The (fromFile(file) mkString) needs parenthesis in order to compile. When removed I get the following error:

Caesar.scala:24: error: not found: value map
    def encrypt(file:String,k:Int) = fromFile(file) mkString map caesar(k)_
                                                                 ^
one error found

mkString obviously returns a string on which (by implicit conversion AFAIK)I can use the map function.

Why does this particular case needs parentheses? Is there a general guideline on when and why you need it?

like image 585
Felix Avatar asked Apr 08 '11 08:04

Felix


People also ask

Can a postfix have parentheses?

The postfix form requires no parentheses. The order of the operators in the postfix expressions determines the actual order of operations in evaluating the expression, making the use of parentheses unnecessary.

What is infix notation in Scala?

For a long time, Scala has supported a useful “trick” called infix operator notation. If a method takes a single argument, you can call it without the period after the instance and without parentheses around the argument.

What is operator in infix?

infix operator (plural infix operators) (computing) an operator that is placed in between the operands like it is commonly used in arithmetical and logical formulae and statements. The plus sign in "2 + 2" is placed as an infix operator in arithmetic.


1 Answers

This is what I put together for myself after reading the spec:

  • Any method which takes a single parameter can be used as an infix operator: a.m(b) can be written a m b.
  • Any method which does not require a parameter can be used as a postfix operator: a.m can be written a m.

For instance a.##(b) can be written a ## b and a.! can be written a!

  • Postfix operators have lower precedence than infix operators, so foo bar baz means foo.bar(baz) while foo bar baz bam means (foo.bar(baz)).bam and foo bar baz bam bim means (foo.bar(baz)).bam(bim).
  • Also given a parameterless method m of object a, a.m.m is valid but a m m is not as it would parse as exp1 op exp2.

Because there is a version of mkString that takes a single parameter it will be seen as an infix opertor in fromFile(file) mkString map caesar(k)_. There is also a version of mkString that takes no parameter which can be used a as postfix operator:

scala> List(1,2) mkString
res1: String = 12

scala> List(1,2) mkString "a"
res2: String = 1a2

Sometime by adding dot in the right location, you can get the precedence you need, e.g. fromFile(file).mkString map { }

And all that precedence thing happens before typing and other phases, so even though list mkString map function makes no sense as list.mkString(map).function, this is how it will be parsed.

like image 137
huynhjl Avatar answered Oct 07 '22 06:10

huynhjl