In this Scala 2.13 example:
import scala.language.implicitConversions
object Main2 extends App {
trait Foo {
type F = this.type => String
}
def fooA[A <: Foo](f: A#F, toString: A#F => String): String = toString(f)
def fooB[A <: Foo](f: A#F, toString: (A => String) => String): String = toString(f)
}
It fails with:
type mismatch;
found : _1.type => String where val _1: A
required: A => String
def fooB[A <: Foo](f: A#F, toString: (A => String) => String): String = toString(f)
Why is A => String
not the same as _1.type => String where val _1: A
?
Is it safe to cast f.asInstanceOf[(A => String)]
?
Is there a concrete example where this doesn't work?
I think you have misunderstanding what is this.type
. From scala 2.13 spec:
Every value in Scala has a type which is of one of the following forms. A singleton type is of the form p . p.type. Where p p is a path pointing to a value which conforms to scala.AnyRef, the type denotes the set of values consisting of null and the value denoted by p p (i.e., the value v v for which v eq p)
It means, that this.type
will be uniq for each instance of Foo
. In fooB
:
def fooB[A <: Foo](f: A#F, toString: (A => String) => String): String = toString(f)
compiler sees that you tries to pass f
which type is:
(some object of A which upper-bouned by Foo).type => String
function from singleton-type object
to String
into function what takes function from object of type A
into String
.
Note object of type A
(new A()
) has not the same type as (new A()).type
, they have different types and this is the reason why compiler shows you an error.
for example, you can write something like that and it will compiles:
class Bar extends Foo {
def conversion: this.type => String = b => "bar"
}
def someStringConversion[A <: Foo]: A#F => String = ???
val bar: Bar = new Bar
someStringConversion[Bar](bar.conversion)
val conversionType: bar.type => String = bar.conversion
val customConversion: bar.type => String = (x: bar.type) => "some string"
someStringConversion[Bar](customConversion)
because of bar.type
has the same type as this.type
(they are both refer into one singleton type - bar.type
Your functions fooA
and fooB
have different signatures, A#F => String
is not the same as A => String
and you can't use asInstanceOf
on first. fooB
will not work on any instance of Foo
because any Foo
instance has it's own this.type
singleton type. It doesn't relate to Foo
like some Foo
implementation relates to Foo
.