简体   繁体   中英

How to specify linked types for asInstanceOf

The title is not too descriptive, but I'm not aware how the used pattern is properly called. I hope all would become clear with example.

trait OneKnot[K <: Knot[K]] { this : K#One =>
  type OK = K // for example only. To show that it is actually defined
  def use(second : OK#Two)
}
trait TwoKnot[K <: Knot[K]] { this : K#Two => }

trait Knot[K <: Knot[K]] {
  type One <: OneKnot[K]
  type Two <: TwoKnot[K]
}

trait KnotExample extends Knot[KnotExample] {
  override type One = OneExample
  override type Two = TwoExample
}

trait OneExample extends OneKnot[KnotExample]
trait TwoExample extends TwoKnot[KnotExample]

object Test {
  def testByName( one : OneExample, two : TwoExample ) = one.use(two)
  def testByKnot[K <: Knot[K]]( one : K#One, two : K#Two ) = one.use(two)
  def testByCast(knot : Knot[_], one : OneKnot[_], two : TwoKnot[_]) = one.asInstanceOf[knot.One].use(two.asInstanceOf[knot.Two])
  def testByInnerCast(one : OneKnot[_], two : TwoKnot[_]) = one.use( two.asInstanceOf[one.OK#Two] )
}

Types OneExample and TwoExample is normally recognized by each other. The testByKnot method shows it. I can also call the use method with static parametrization by Knot . The types would be compatible, as shown in the testByKnot method.

But I need to discard type information to store data in a collection. eg Map[Knot[_], OneKnot[_]] . So I need to restore types after extraction from collection using asInstanceOf . But I failed to specify correctly to what types the cast needed.

In the last two test methods I get two corresponding errors:

NotSameType.scala:25: error: type mismatch;
 found   : knot.Two
 required: _$1#Two
  def testByCast(knot : Knot[_], one : OneKnot[_], two : TwoKnot[_]) = one.asInstanceOf[knot.One].use(two.asInstanceOf[knot.Two])
                                                                                                                      ^
NotSameType.scala:26: error: type Two is not a member of one.OK
  def testByInnerCast(one : OneKnot[_], two : TwoKnot[_]) = one.use( two.asInstanceOf[one.OK#Two] )

How the cast should be done properly?

How about using type K <: Knot[K] to glue/cast the two knots types together?

object Test {
  def testByName(one: OneExample, two: TwoExample) = one.use(two)
  def testByKnot[K <: Knot[K]](one: K#One, two: K#Two) = one.use(two)
  def testByCast[K <: Knot[K]](one: OneKnot[_], two: TwoKnot[_]) =
    one.asInstanceOf[K#One].use(two.asInstanceOf[K#Two])
  def testByInnerCast[K <: Knot[K]](one: OneKnot[_], two: TwoKnot[_]) =
    one.asInstanceOf[K#One].use(two.asInstanceOf[K#One#OK#Two])
}

You can then call one of the cast methods directly.

val one    = new OneExample { def use(second: TwoExample) = ??? }
val two    = new TwoExample {}
val result = testByCast(one, two)

The answer summarize approach suggested by Andy

You may use type parametrization but never specify the needed tag. see the sample:

def testByDiscard[K <: Knot[K]]( one : OneKnot[_], two : TwoKnot[_] ) =
  one.asInstanceOf[K#One].use(two.asInstanceOf[K#Two])

The mystery is that compiler managed to substitute something meaningful to the type parameters. The type parameter may never be specified, but this construction would still works. Anyway java gets rid of all type parameters, so no crucial information is lost.

I was curious what is the magic type the compiler use. And add implicit type tag to get it. It was just simple Nothing not a complicated type erasure type. Static type checker really does not complain agains the further usage:

val exo : OneExample = new OneExample
val ext : TwoExample = new TwoExample
Test.testByDiscard[Nothing](exo, ext)

But fails as expected when trying to cast directly to Nothing#One or Nothing#Two . It also fails when trying with calling testByKnot[Nothing] that is identical to discard case but without asInstanceOf call. It is quite amusing how the scala type manager works, but it deserves separate question.

This question is closed with answer provided by Andy and detailed by me above. It just works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM