Reputation: 799
Let me get straight into the problem that I faced while hanging around with type bounds.
Let's consider the following...
I created a function 'foo' like this
def foo[A,B](x:A,y:B):(A,B)=(x,y)
I invoked foo in scala worksheet, like
foo("Mars",2400)
I obtained a result like
res0: (String, Int) = (Mars,2400)
Notice the inferred types of Mars and 2400
Now I wanted to enforce that the function 'foo' accepts Integers or floats or Doubles (any type that is a subtype of AnyVal).
To enforce I wrote a code like
def fooNew[A<:B,B](x:A,y:B):(A,B)=(x,y)
The inferred types from the previous code was (String,Int) and when I invoked fooNew like
fooNew("Saturn",2400)
I was surprised to see that the compiler did let my code pass and did not raise the error instead it did give an output like
res0: (String, Any) = (Saturn,2400)
Now, the desired way of enforcing did not work here. Had I done something like this
def fooNew[A<:B,B<:AnyVal](x:A,y:B):(A,B)=(x,y)
The compiler would have surely raised an error for me and it did!
Error:(2, 2) inferred type arguments [String,Any] do not conform to method fooNew's type parameter bounds [A <: B,B <: AnyVal]
fooNew("Saturn",2400);}
I want to ask, why didn't the compiler the type as Int instead it inferred the type Any and let my code pass the type checks?
Do I always need to enforce the second type to be a subtype of AnyVal instead of letting the compiler infer it for me? or is it a bug in the compiler.
Seek pardon if you found my question misleading or not upto your expectations.
Currently I am using scala-library 2.11.8
Thankyou
Upvotes: 0
Views: 50
Reputation: 170733
You can think of using your original declaration with inferred types as "find A
and B
such that x
has type A
, y
has type B
, and A
is a subtype of B
". Since A = String
and B = Any
satisfy these conditions, the compiler correctly infers them (there are also other solutions, e.g. A = B = Any
, but this one is the most specific).
But you can change the declaration to tell the compiler "find A
and B
such that x
has type A
and y
has type B
, and then check that A
is a subtype of B
". This is done as follows:
def fooNew[A,B](x:A,y:B)(implicit evidence: A <:< B): (A,B)=(x,y)
This works because the compiler will only use the first parameter list to infer A
and B
. Search for "generalized type constraints" to find more information about <:<
and =:=
.
Upvotes: 2
Reputation: 2101
def fooNew[A<:B,B](x:A,y:B):(A,B)=(x,y)
In the above you are declaring type parameter A to be a subtype of type parameter B. When you pass A as String and B as Int, the compiler goes up the class hierarchy to find a suitable type for B such that Int is a B and also String is a subtype of B. The only type in the heirarchy which satisfies these two conditions is the Any
type. So, String is a subtype of Any and Int is of type Any
Upvotes: 3