Confused by specification of overloading resolution


#1

There are some things I don’t understand about how overloading resolution is specified:

In the definition of being as specific as and more specific than there’s a rule that says:

Given two members of types T and U which are neither parameterized nor polymorphic method types, the member of type T is as specific as the member of type U if the existential dual of T conforms to the existential dual of U. Here, the existential dual of a polymorphic type [a1 >: L1 <: U1,…,an >: Ln <: Un]T is T forSome { type a1 >: L1 <: U1 ,…, type an >: Ln <: Un}. The existential dual of every other type is the type itself.

First, this rule assumes that types T and U are not polymorphic but then it uses the notion of existential dual which is needed only for polymorphic types. Why?


#2

Sounds like an extremely convoluted way of saying

Given two members of types T and U which are neither parameterized nor polymorphic method types, the member of type T is as specific as the member of type U if T conforms to U.

Also, what is the difference between parameterized and polymorphic in the context of method types?


#3

Parameterized method is a method that takes parameters.
Polymorphic method is a method that takes type parameters.


#4

Good question, I’d like to know too! It says “T and U are neither … method types”. Can members in Scala 2 have polymorphic types that are not method types?


#5

I stumbled upon this problem when trying to precisely answer this SO question. I tried to follow the specification step by step and realized something’s wrong.

Let’s try it again. We have a typeclass and two polymorphic implicit defs for it:

trait Base
class Klass extends Base

trait TC[T]
object TC {
  implicit def unbounded[T]: TC[T] = new TC[T] {}
  implicit def bounded[T <: Base]: TC[T] = new TC[T] {}
}

Now, if we demand implicitly[TC[Klass]], the compiler will chose bounded, but I can’t see how this can be deduced from the specification. Let’s try:

First, we need to follow specificity rules in order to find out if bounded is as specific as unbounded and vice versa.

The specification says:

A polymorphic method of type [a1 >: L1 <: U1,…,an >: Ln <: Un]T is as specific as some other member of type S if T is as specific as S under the assumption that for i=1,…,n each ai is an abstract type name bounded from below by Li and from above by Ui.

Applying this to bounded and unbounded we get two polymorphic method types [T <: Base]A[T] and [T]A[T]. The rule above apparently wants me to somehow “strip” the type parameter from [T <: Base]A[T] and leaving something like type T <: Base; A[T] (which is not the same as A[T] forSome { type T <: Base }?). Then, I have to decide whether type T <: Base; A[T] is as specific as [T]A[T]. The first type is no longer polymorphic while the second one still is, so the next rule to apply is:

A member of any other type is always as specific as a parameterized method or a polymorphic method.

This way we deduce that bounded is as specific as unbounded.
However, using exactly the same logic we could deduce that unbounded is as specific as bounded and type bounds have absolutely no influence on that.
This would in turn mean that neither bounded is more specific than unbounded nor the other way around which would mean that bounded should not be chosen over unbounded and we should get an ambiguous implicits error.

So this already falls apart here, before we even get to the rule that I initially asked about.
Either I’m missing something or it seems that this specification is off.


#6

I’d like to bring this one more time. Is there anyone that understands the specification?


#7

I’m going to program a hot key to the phrase, “The specification is too complex for my english.”, from the SO comment.

I understand the first question to pertain to:

scala 2.13.0-M4> trait T { type X <: Int ; implicit val xs: List[X] ; implicit val ys: List[AnyVal] }
defined trait T

scala 2.13.0-M4> { val t: T = null ; import t._ ; implicitly[List[_]] } //print

{
  val t: $line11.$read.$iw.$iw.T = null;
  import t._;
  scala.Predef.implicitly[(scala.`package`.List[_$1] forSome { 
    type _$1
  })](t.xs)
} // : List[_$1]

and I understand the second question to mean the same thing, where T in bounded “is an abstract type name”, where “name” means “member”.

The two values in contention are TC, one with a member type T and the other with a member type T <: Base. Probably you’re saying the same thing, but I don’t follow what you mean at “the first type is no longer polymorphic”. I just take the type T <: Any for the unbounded case, if that is what you mean. I’m speaking inexpertly; I’ve walked through this section some time ago.

But I can’t wait for someone who knows to come back from vacation. I’m actually on vacation, of a sort, and for me this is a kind of type system cosplay. I’m actually wearing my furry Adriaan hat!


#8

I had a polymorphic type [T <: Base]A[T] and then the specification told me to take the A[T] part from it and assume that “for i=1,…,n each ai is an abstract type name bounded from below by Li and from above by Ui” which in this case means "T is an abstract type name bounded from above by Base". So I believe the specification told me to drop the type parameter from my polymorphic type and therefore it’s no longer polymorphic. But I’m not really sure how to interpret the resulting type.


#9

So, I’m going to bump this question once again because I have an increasing feeling that the specification may be a specifiction. I would really like to understand how this overloading resolution should work. Please don’t leave it as “black magic” for me :frowning:

To make the question more focused, I would really appreciate a step-by-step explanation of why bounded has priority over unbounded in the mentioned example (based on the specification)

trait Base
class Klass extends Base

trait TC[T]
object TC {
  implicit def unbounded[T]: TC[T] = new TC[T] {}
  implicit def bounded[T <: Base]: TC[T] = new TC[T] {}
}

#10

I had this tab open all the time, still trying to find time to (hopefully) answer it…