2

In scala the following works

1 max 2

But the following don't

1 Math.pow 2

or

import Math.pow
1 pow 2

Can you explain why?

Oli
  • 9,766
  • 5
  • 25
  • 46
Bunny Rabbit
  • 8,213
  • 16
  • 66
  • 106
  • do you mean `math` lowercase? – joel May 09 '19 at 07:35
  • 2
    Possible duplicate of [When to use parenthesis in Scala infix notation](https://stackoverflow.com/questions/5592642/when-to-use-parenthesis-in-scala-infix-notation) – joel May 09 '19 at 07:38
  • I think there is some overlap, but not a complete duplicate. The 1 pow 2 (and 1 Math.pow 2) question is about methods available after an implicit conversion of 1 to Int (of which pow is not an available method). – GMc May 09 '19 at 08:17
  • Infix notation sucks. – Lasf May 09 '19 at 14:00

6 Answers6

5

There are a couple of things going on here. In a nutshell:

  • Implicit casting of the constant "1" to an instance of Int
  • Leveraging of the "Space notation" for methods that take a single parameter

In the case of 1 max 2, the constant 1 is implicitly cast as an Int (i.e. an instance of class Int).

Since the Int class defines a method called "max" which takes a single parameter, you can use the space or infix notation. The following are all equivalent (run in spark-shell):

scala> 1 max 2
res8: Int = 2

scala> 1.max(2)
res9: Int = 2

scala> val x = 1     // Note the result type here is Int
x: Int = 1

scala> x.max(2)
res10: Int = 2

scala> x max (2)
res11: Int = 2

scala> 1            // Note the result type here is *also* Int
res12: Int = 1

scala> 1.           // Here are all of the methods that are defined for an Int
!=   +    <<   >>             byteValue     ensuring     formatted    isInfinity      isValidByte    isWhole     notify       signum           toChar        toInt           toString     until   
##   -    <=   >>>            ceil          eq           getClass     isInstanceOf    isValidChar    longValue   notifyAll    synchronized     toDegrees     toLong          unary_+      wait    
%    ->   ==   ^              compare       equals       hashCode     isNaN           isValidInt     max         round        to               toDouble      toOctalString   unary_-      |       
&    /    >    abs            compareTo     floatValue   intValue     isNegInfinity   isValidLong    min         self         toBinaryString   toFloat       toRadians       unary_~      →       
*    <    >=   asInstanceOf   doubleValue   floor        isInfinite   isPosInfinity   isValidShort   ne          shortValue   toByte           toHexString   toShort         underlying           

Note that there are a whole bunch of methods available on an Int for example max, min, +, - and so on. Looking at the signature of say, +, we can see that + is a method that takes a single parameter. Therefore we can do the following:

scala> 1 + 2     // No surprises here
res15: Int = 3

scala> 1.+(2)    // Huh? This works because + is a method of Int that takes a single parameter.
                 // This is effectively the same as your max example.
res16: Int = 3

scala> 1.+       // Here are the signatures of the + method.
   def +(x: Char): Int
   def +(x: Long): Long
   def +(x: Float): Float
   def +(x: Short): Int
   def +(x: Double): Double
   def +(x: Byte): Int
   def +(x: String): String
   def +(x: Int): Int

scala> 1 + 'A'   // From the above, we can see that the following is also valid
res17: Int = 66  // because the return type is Int

scala> 1 + "41"
res18: String = 141   // In this case, the + operator is a String concatenation operator Because the return type is String

scala> 1 + "x"
res19: String = 1x    // Also because the return is String, but possible more intuitive.


To the pow part of the question.

Math.pow is a method that takes 2 parameters. Because it takes 2 parameters the space notation is not available to you. Also, pow is not a method that is associated with an Int. It is pretty much like a static method of the Math class (actually Math is an object). So, just like you can't say x.pow(y,z) you can not say 1.pow(y, z) on the other hand you can say Math.pow(x, 2) - to get x squared - because that matches the signature of the pow method.

Here is the signature of Math.pow:

scala> Math.pow
   def pow(x$1: Double,x$2: Double): Double

This is a little less exciting than +, but it is clear that it takes 2 Doubles and returns a Double. The example of say Math.pow(2,2) works even though integers are supplied as parameters (when Doubles are required) because the Ints are automatically cast to Double.

I hope this helps explain what you are seeing. I encourage you to try these examples in spark-shell, sbt or some other scala REPL.

GMc
  • 1,764
  • 1
  • 8
  • 26
3

Methods doesn't the same signature:

override def max(that: Long): Long

def pow(x$1: Double,x$2: Double): Double

The first is a member of Int* and can be called on 1 whereas the second is called on Math object and must have two parameters.

* well actually of RichInt by implicit conversion, but to an intuitive use perspective, it comes to the same thing so this subtlety shouldn't bother you

2

Method:

override def max(that: Int): Int = math.max(self, that)

is from scala.runtime.RichInt class bc evry Int is wrapped by:

@inline implicit def intWrapper(x: Int)         = new runtime.RichInt(x)

of class scala.LowPriorityImplicits

But RichInt doesn't have any pow method. And you have to respec Math.pow signature:

public static double pow(double a, double b)

and call it with 2 arguments or use your own developed wrapper, like:

object MainClass {

  implicit class IntHelper(i:Int) {
    def pow(p:Int): Double = Math.pow(i, p)
  }

  def main(args: Array[String]): Unit = {
    println(1 pow 2)
  }
}

output:

1.0
Matthew I.
  • 1,793
  • 2
  • 10
  • 21
1

1 max 2 is just syntactic sugar for 1.max(2).

As 1 is an integer literal, all methods defined for scala.Int can be applied in this way. Unfortunately pow is not a method of scala.Int

But you can find the related method in scala.math.BigDecimal and scala.math.BigInt.

So the following would work:

BigInt(1) pow 2
det0
  • 281
  • 2
  • 5
0

The max function you have used is from Int.

It's signature is:

def max(that: Int): Int

Since 1 is an Int, you can call 1 max 2 with infix notation. it is simply 1.max(2).

The pow function is from Math. It's signature is

def pow(x: Double, y: Double): Double

Since 1 is not a Math, you can't simply call 1 pow 2. On the other hand in Int, there is no method such that def pow(that: Int): Int.

The one you can use is pow(a,2) which is the Math implementation.

Supun Wijerathne
  • 11,964
  • 10
  • 61
  • 87
-2

Scala.Math Documentation says that pow function takes two arguments of type Double and returns the value of the first argument raised to the power of the second argument.

This is the working version of the pow function:

import Math.pow

val a: Double = 1

pow(a,2) // returns 1.0
Yayati Sule
  • 1,601
  • 13
  • 25