Aniruddha Sinha
Aniruddha Sinha

Reputation: 799

Subtyping leads to Any: Bug in compiler or issue with my code?

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

Answers (2)

Alexey Romanov
Alexey Romanov

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

Samar
Samar

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

Related Questions