implicit conversion over multiple levels, why does int to double automatically work? - scala

I was always figuring implicit conversions over multiple levels is not possible in scala (unless you define view bounds: http://docs.scala-lang.org/tutorials/FAQ/context-and-view-bounds.html)
But it seems that there is a flaw in the type system or an inconsistency.
Following an example (adapted from How can I chain implicits in Scala?)
class A(val n: Double){
def total = n + 10
}
object T1{
implicit def toA(n: Double): A = new A(n)
val i : Int = 5
println(i.total) //Why does this work?
println(5.2.total)
}
I do not really understand why the implicit conversion from Int -> Double -> A works. Can someone please explain the reasons? Thanks

It happens via a different mechanism, unique to the numeric types, called numeric widening.
SLS 6.26.1 Value Conversions says:
The following five implicit conversions can be applied to an expression e which has some value type T and which is type-checked with some expected type pt.
Static Overloading Resolution
Type Instantiation
Numeric Widening
Numeric Literal Narrowing
Value Discarding
View Application
Dynamic Member Selection
(Okay, that's more than five....not sure why :)
The one of interest is numeric widening:
If e has a primitive number type which weakly conforms to the expected type, it is widened to the expected type using one of the numeric conversion methods toShort, toChar, toInt, toLong, toFloat, toDouble defined here.
3.5.16 Weak Conformance says
In some situations Scala uses a more general conformance relation. A type S weakly conforms to a type T, written S<:wT, if S<:T or both S and T are primitive number types and S precedes T in the following ordering.
Byte <:w Short
Short <:w Int
Char <:w Int
Int <:w Long
Long <:w Float
Float <:w Double
So println(i.total) becomes println(i.total.toFloat) because Int <:w <: Long <: Float.
Java (and C# and many other languages) have numeric widening, and Scala decided to keep it.
Note that the reverse does not work: a Float cannot be implicitly converted to Int via this way, since magnitude could be lost; it's not a "widening".
You can add -Ywarn-numeric-widen and get a warning when this happens.

As Gabor already commented, this is due to numeric widening. If you run with the -print option, you will see that a .toDouble is appended to the i, which then allows it to use the toA implicit. You can run scalac with the warn-numeric-widen and this will at least give you the following:
<console>:14: warning: implicit numeric widening
println(i.total) //Why does this work?
^

Related

Scala equivalent of Java's Number with divide method

I want to generalise this function
def selfSufficiency(a: Seq[Double], b: Seq[Double]): Double =
a.sum/b.sum
I tried using the ideas provided here to implement a more general function that work with Doubles, Floats, Ints, etc.:
def selfSufficiency[A](a: Seq[A], b: Seq[A])
(implicit n: Numeric[A]):A = {
import n._
a.sum/b.sum
}
I however get a remark from eclipse saying that
value / is not a member of type parameter A.
1- How can I implement this in functional/generalisable way?
2- Does my implementation limits the user to have the same type "A" for both inputs? In other words, can I do this with my code?
selfSufficiency(Seq(1,2,3), Seq(2.0,1.3))
if I cannot, please explain how to implement this?
Please note that the code here provide a toy example. In my production function, I add, subtract, find the larger number, etc.
The problem is that Numeric doesn't encode the division function - you need a Fractional.
Thus your code becomes
def selfSufficiency[A](a: Seq[A], b: Seq[A])
(implicit n: Fractional[A]):A = {
import n._
a.sum/b.sum
}
And now it works.
Edit
I just read this part of your question.
Does my implementation limits the user to have the same type "A" for both inputs? In other words, can I do this with my code?
Because both Fractional and Numeric are parametrized in just one T, both arguments have to be from the same type - for example take a look to the div function.
However, since numeric values of less precision are subtypes of the ones with higher (fig 1). You can make it work by upcast, but you will need to help the compiler a little more.
selfSufficiency[Double](Seq(1,2,3), Seq(2.0,1.3)) // res1: Double = 1.8181818181818183
Note: Without specifying the type as Double, the compiler will yield the following error.
error: could not find implicit value for parameter n: Fractional[AnyVal]
fig 1
Reference: https://www.artima.com/pins1ed/scalas-hierarchy.html
What you are looking for is the Fractional trait which is a more narrow Numeric (subtype) that supports div.

How does scala infers the type of a variable?

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.

Rounding numeric parameter types in Scala

I'm experimenting with a method in Scala which is attempting to round numbers depending on how big they are, e.g. if the value is below 1 then it makes sense to round it by at least one decimal point; rather than remaining an integer. Here's what I'm trying:
def roundSmart[A](num: A)(implicit numeric: Numeric[A]) = num match {
case num if num < 1 => numeric.toDouble(num)
case _ => numeric.toInt(num)
}
Which throws this error:
value < is not a member of type parameter A
Of course the parameters need to accept a range of parameter types within the function signature as it may be taking integers or doubles so this has added a further complexity.
I've taken the conditional statement on the first case from this answer -
Using comparison operators in Scala's pattern matching system and am eager to use a Functional Programming approach. Perhaps there is also some in-built scala function like Math.round() that could help to round the second condition rather than remove any decimals. Thanks!
TL;DR : every numeric methods you'll need are inside numeric
The error is self-explanatory: your type A (which is generic) does not have a < method.
However, what you have is a typeclass with all numeric methods in it, so you should probably import them:
import numeric._
This imports (among other things) implicit conversion to OrderingOps, which has the desired method. But this comparison cannot work, since 1 is not an A, it's an Int!
The solution is simply to use fromIntof numeric.
While we're at it, you will have unexpected results for input such as -234.2e123... You'd better do your test on the absolute value of your number (abs is also a method of numeric).
Also, if you want to do a simple test, there is no need to use pattern matching, a if else statement is enough
def roundSmart[A](num: A)(implicit numeric: Numeric[A]) = {
import numeric._
if (abs(num) < fromInt(1)) toDouble(num) else toInt(num)
}

Scala add value to a char variable

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

type parameters and numeric widening

As we know, we can add (subtract/multiply/etc.) two numbers of different Numeric types and the result will be the wider of the two types, regardless of their order.
33F + 9L // Float + Long == Float
33L + 9F // Long + Float == Float
This is because each of the 7 Numeric classes (Byte, Short, Char, Int, Long, Float, Double) has 7 different +() methods (and -(), *(), etc), one for every Numeric type that can be received as a passed parameter. [There's an extra +() method for handling a String parameter, but that need not concern us here.]
Now consider the following:
implicit class PlusOrMinus[T: Numeric](a: T) {
import Numeric.Implicits._
def +-(b: T) = if (util.Random.nextBoolean) a+b else a-b
}
This works if the two operands are the same type, but it also works if the type of the 1st operand is wider than the type of the 2nd.
11F +- 2L // result: Float = 9.0 or 13.0
I believe what's happening here is that the compiler uses weak conformance to achieve numeric widening on the 2nd operand (the b parameter) as it is passed to the +-() method.
But the 1st operand won't be widened to match the 2nd. It won't even compile.
11L +- 2F // Error: type mismatch; found: Float(2.0) required: Long
Is there any way around this limitatiion?
I can't use a different type parameter for the b argument (def +-[U: Numeric](b: U) = ...) because a Numeric, expressed via a type parameter, can only add/subtract it's own type.
Is the only solution to create 7 different classes (PlusOrMinusShort/Int/Long/etc.) with 7 different methods (def +-(b:Short), def +-(b:Int), def +-(b:Long), etc.)?
Here is a way:
implicit class PlusOrMinus[T: Numeric](a: T) {
import Numeric.Implicits._
def +-(b: T) = plusOrMinus(a,b)
def +-[U: Numeric](b: U)(implicit ev: T => U) = plusOrMinus[U](a,b)
private def plusOrMinus[W: Numeric](a: W, b: W): W =
if (util.Random.nextBoolean) a+b else a-b
}
Then, with this, I get the following interaction:
scala> 11F +- 2L
res0: Float = 9.0
scala> 11L +- 2F
res1: Float = 9.0
The idea is that if I could just have a function plusOrMinus, this whole problem would be trivial, since the same widening could happen for either arguments. After defining such a function, the problem becomes how to embed it into an implicit class to use it in an infix form.
Here, we have only two cases: either the second argument needs to be widened or the argument wrapped by the implicit class needs to be widened. The first of these cases is covered by the first +- method (for the reasons you observed above). For the second, however, we need to explicitly say that there is some conversion that is possible and pass the generic type of the conversion to plusOrMinus.