I am creating a simple function in Scala
def addOne(m: Int): Int = m + 1
Using it with integers works normally, using double it throws a type mismatch error.
addOne(2) = 3
addOne(2.1) = error: type mismatch
When I use it with a character in double quotes, it throws a type mismatch as expected.
addOne("z") = error: type mismatch
However, when using a single quotes character it returns a value for that letter.
addOne('z') = 123
What is happening here and why is it like this?
The reason you can use a Char as an argument to a function taking an Int is because Scala performs an implicit conversion from Char to Int. This specific conversion is defined in the companion object of the Char class. See here:
http://www.scala-lang.org/api/2.12.1/scala/Char$.html (It seems like SO breaks this link at the $ character. Copy-paste it instead)
The function perfoming the conversion is called char2int. It converts the Char into its corresponding Unicode value as an Int.
When the Scala compiler sees that the types Char and Int don't match, it will first check if there are any available implicit conversions. It only gives a compile error if it didn't find any. If it finds an implicit conversion, it will insert that function call into your code. Your code is therefore transformed to this:
addOne(Char.char2int('z'))
If you want to make your own implicit conversion to, for example, let your function accept String, you can define this:
// Enable implicit conversions.
import scala.language.implicitConversions
// The "implicit" modifier is the important part here, not the name of the function.
implicit def string2int(s: String) = s.toInt
Now this compiles:
// This returns 6
addOne("5")
/*
* This throws a NumberFormatException due to my implementation of string2int.
* Create your own implementation of string2int if you want it to work properly.
*/
addOne("a")
Finally: Beware that implicit conversions are very powerful and therefore can be dangerous! See TheArchetypalPaul's comment for an explanation.
It is because addOne(m: Int) [The part after colon (:) ] tells Scala you will pass Int to it, not Double, not anything else.
if you want it to work for Double, try this, but then you will always get Double as Result.
def addone (m : Double ) = m+1
addone: (m: Double)Double
scala> addone(1)
res0: Double = 2.0
scala> addone(1.1)
res1: Double = 2.1
Scala map the char type using the ASCII Table. So, 'z' is mapped to 122, which is an integer. In the method, addOne('z'), the input parameter been cast to an integer (i.e. 122).
However, the input parameter in addOne(2.1) is 2.1, which is a double and in addOne("z") is a string. They cannot be cast to an integer automatically.
def addOne(m: Int): Int = m + 1 only accept an integer for m
It also work with a single quoted character (z) because it's translated into its ASCII value. The value for 'z' is 122 and you add 1.
scala> val foo: Int = 'z'
foo: Int = 122
scala> val bar = foo + 1
bar: Int = 123
If you want to make this working with double you can specify def addOne(m: Double): Double = m + 1
Related
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?
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.
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
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
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
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.
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
I am always fascinated to see how scala always infers the type correctly . How scala does it?
scala> val num = 5
num: Int = 5
scala> val num = "5"
num: String = 5
I know it might be a very stupid question to ask here but i don't know the answer.
Please enlighten me.
Thanks!
There are several methods for inferencing the type of a variable. Mainly using those called inference rules based in logic theory.
There are plenty of papers explaining the theory behind. Here I put a good example (with Scala ;) )
www2.in.tum.de/hp/file?fid=879
While parsing the code compile can infer that 5 is of type Int and "5" is of String type.
In simple terms any value enclosed in double quotes " will be considered String, value enclosed in single quote ' is considered Char and digits are considered Int (unless specified otherwise).
This is further used to used to infer types for expression results.
Consider this example
val a = 5 // translates to val a:Int = 5
val b = "5" // translates to val b:String = "5"
val x = a+1 // expression 1
val y = b+1 // expression 2
In this example the code type of a is inferred as Int and type of b is inferred as String.
Based on this expression 1 calls function Int.+(x: Int): Int which returns Int, hence type of x is guessed to be Int.
Similarly expression 2 calls function StringOps.+(arg0: Any): String which returns String, hence type of y is guessed to be String.
In Scala, if I have a variable declaration, e.g.
var x: Char = 'a'
If I then try and update this character by adding 1, e.g.
x = x + 1
I get a compilation error: Type mismatch, found Int required Char. However, I can do this without a compilation error:
x = 'a' + 1
I'm guessing this has something to do with literal values vs objects, however, I'm trying to get my head around the exact behaviour. You can clearly assign a literal integer to a Char, e.g. 97, and you can also assign the result of 97-32. However if I say 97-32+5 then I get a type mismatch error. At what point does the compiler differentiate between an expression that results in a literal vs one that result in an object?
Assignment is the key here.
Look at the following REPL session:
alex#POSITRON ~ $ scala
Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_131).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val x:Char = 'a'
x: Char = a
scala> x + 1
res0: Int = 98
scala> var y:Char = 'a'
y: Char = a
scala> y + 1
res1: Int = 98
scala> y = y + 1
<console>:8: error: type mismatch;
found : Int
required: Char
y = y + 1
^
scala>
So as you can see unless you try to reassign the variable values everything goes fine. When you write 'a'+1 or x + 1 it gets converted to Int.
So when you finally try to x = x + 1 reassign then you are trying to assign Int value to the Char variable. This explain why compilation error occurs.
In the Char companion object there is implicit def char2int(x: Char): Int method.
I think in var x:Char = 'a' + 1 the first thing which happens is invocation of this method to convert 'a' to 97. Then 97 is added 1, both as Ints. Then the variable x gets instantiated in the same way as in val y:Char = 98. This I think explains how variable initialization works.
There's a special rule for typing literals in the spec.
However, if the expected type pt of a literal in an expression is
either Byte, Short, or Char and the integer number fits in the numeric
range defined by the type, then the number is converted to type pt and
the literal's type is pt.
That lets you write:
scala> 97 : Char
res0: Char = a
scala> 97 + 1 : Char
res1: Char = b
Sneakily, they mean constant expressions here. But the definition of constant expression is platform-specific, so technically res1 could also fail to compile, if it were not constant-folded.
A related question about constant folding in scaladoc shows the weird loss of type checking under scaladoc:
$ ~/scala-2.12.3/bin/scaladoc -d /tmp folded.scala
folded.scala:9: error: type mismatch;
found : Int
required: Char
x = 'a' - 32 + 5
^
model contains 4 documentable templates
one error found
I'm trying to have curried apply and update methods like this:
def apply(i: Int)(j: Int) = matrix(i)(j)
def update(i: Int, j: Int, value: Int) =
new Matrix(n, m, (x, y) => if ((i,j) == (x,y)) value else matrix(x)(y))
Apply method works correctly, but update method complains:
scala> matrix(2)(1) = 1
<console>:16: error: missing arguments for method apply in class Matrix;
follow this method with `_' if you want to treat it as a partially applied function
matrix(2)(1) = 1
Calling directly update(2)(1)(1) works, so it is a conversion to update method that doesn't work properly. Where is my mistake?
The desugaring of assignment syntax into invocations of update maps the concatenation of a single argument list on the LHS of the assignment with the value on the RHS of the assignment to the first parameter block of the update method definition, irrespective of how many other parameter blocks the update method definition has. Whilst this transformation in a sense splits a single parameter block into two (one on the LHS, one on the RHS of the assignment), it will not further split the left parameter block in the way that you want.
I also think you're mistaken about the example of the explicit invocation of update that you show. This doesn't compile with the definition of update that you've given,
scala> class Matrix { def update(i: Int, j: Int, value: Int) = (i, j, value) }
defined class Matrix
scala> val m = new Matrix
m: Matrix = Matrix#37176bc4
scala> m.update(1)(2)(3)
<console>:10: error: not enough arguments for method update: (i: Int, j: Int, value: Int)(Int, Int, Int).
Unspecified value parameters j, value.
m.update(1)(2)(3)
^
I suspect that during your experimentation you actually defined update like so,
scala> class Matrix { def update(i: Int)(j: Int)(value: Int) = (i, j, value) }
defined class Matrix
The update desugaring does apply to this definition, but probably not in the way that you expect: as described above, it only applies to the first argument list, which leads to constructs like,
scala> val m = new Matrix
m: Matrix = Matrix#39741f43
scala> (m() = 1)(2)(3)
res0: (Int, Int, Int) = (1,2,3)
Here the initial one-place parameter block is split to an empty parameter block on the LHS of the assignment (ie. the ()) and a one argument parameter block on the RHS (ie. the 1). The remainder of the parameter blocks from the original definition then follow.
If you're surprised by this behaviour you won't be the first.
The syntax you're after is achievable via a slightly different route,
scala> class Matrix {
| class MatrixAux(i : Int) {
| def apply(j : Int) = 23
| def update(j: Int, value: Int) = (i, j, value)
| }
|
| def apply(i: Int) = new MatrixAux(i)
| }
defined class Matrix
scala> val m = new Matrix
m: Matrix = Matrix#3af30087
scala> m(1)(2) // invokes MatrixAux.apply
res0: Int = 23
scala> m(1)(2) = 3 // invokes MatrixAux.update
res1: (Int, Int, Int) = (1,2,3)
My guess is, that it is simply not supported. Probably not due to an explicit design decision, because I don't see why it shouldn't work in principle.
The translation concerned with apply, i.e., the one performed when converting m(i)(j) into m.apply(i, j) seems to be able to cope with currying. Run scala -print on your program to see the code resulting from the translation.
The translation concerned with update, on the other hand, doesn't seem to be able to cope with currying. Since the error message is missing arguments for method apply, it even looks as if the currying confuses the translator such that it tries to translate m(i)(j) = v into m.apply, but then screws up the number of required arguments. scala -print unfortunately won't help here, because the type checker terminates the translation too early.
Here is what the language specs (Scala 2.9, "6.15 Assignments") say about assignments. Since currying is not mentioned, I assume that it is not explicitly supported. I couldn't find the corresponding paragraph for apply, but I guess it is purely coincidental that currying works there.
An assignment f(args) = e with a function application to the left of
the ‘=’ operator is interpreted as f.update(args, e), i.e. the
invocation of an update function defined by f.
EDIT: I'm using Scala 2.9.2
In Scala, I've defined a custom class which wraps a Double:
class DoubleWrap( d : Double ) {
def double( ) = d * 2
}
and an implicit conversion from Double to DoubleWrap:
implicit def wrapDouble( d : Double ) = new DoubleWrap( d )
This allows me to do the following:
scala> 2.5.double
res0: Double = 5.0
However, since there is an implicit conversion in Scala from Int to Double, I can also do the following:
scala> 2.double
res1: Double = 4.0
This operator can also be applied to all elements of a double-type collection using map
scala> List( 1.0, 2.0, 3.0 ).map( _.double )
res2: List[Double] = List(2.0, 4.0, 6.0)
However, if I attempt to apply the function to all elements of an integer collection, it doesn't work:
scala> List( 1, 2, 3 ).map( _.double )
<console>:10: error: value double is not a member of Int
List( 1, 2, 3 ).map( _.double )
Does anyone know why this is the case?
In scala, implicit conversions are not automatically chained. In other words, the compiler will look for a single implicit conversion that will allow the code to make sense, it will never try to apply two (or more) successive implicit conversions.
In your example, the fact that you can do 2.double has nothing to do with the fact that there is an implicit conversion from Double to Int in Predef.
As a proof, try this in the REPL:
scala> val i: Int = 2
i: Int = 2
scala> i.double
<console>:13: error: value double is not a member of Int
i.double
It does not compile.
So why does 2.double compile? Good question.
I thought I understood this intuitively: 2 can be interpreted as the Int value 2 or as the Double value 2.0 in the first place, so my intuition was that 2 is somehow already a Double in this context.
However, I think this is wrong, because even the following will compile, surpisingly: (2:Int).double (or even more strange: ((1+1):Int).double). I'll be honest, I am flabbergasted and have no idea why this compiles while val i: Int = 2; i.double does not.
So to sum up, it is normal that scala does not try to apply two implicit conversions at the same time, but for some reason this rule does not seem to apply to constant expressions.
And now for a way to fix your issue: simply modify your implicit conversion so that it accepts any type that is itself implicitly convertible to Double. In effect, this allows to chain the implicit conversions:
implicit def wrapDouble[T <% Double]( d : T ) = new DoubleWrap( d )
It's a bug which should soon be fixed.