2

So I want to make sure that the extractor in the case match will give an alias to it the correct generic type, if possible.

trait MyT[A]

case class MyC[A](t: MyT[A])

def foo: MyC[_]

def go[A](t: MyT[A]): Option[MyC[A]] = foo match {
  case m@MyC(`t`) => Some(m.copy(t = t))
  case _ => None
}

This works but I would prefer to not do the m.copy(t = t). Basically m@ will bind to MyC[Any], but I want it to bind to MyC[A]. Is this possible, maybe with a custom unapply?

4
  • foo actually returns MyC[_] and its not clear how I would change this in my code. I need to rely on foo. Commented Jul 12, 2018 at 22:01
  • 1
    m.copy(t = t) will just call MyC(t), so you could write that instead and don't need m here (which may not apply to your real code, of course). Of course, reusing m would be better, but this seems to be a strict improvement on copy to me. Commented Jul 13, 2018 at 7:02
  • It's not. If I ever add fields to MyC, I would need to change the case match as well as the result, whereas copy means I only need to change the case match. Commented Jul 13, 2018 at 11:28
  • Only if the added fields aren't related to A, though. Commented Jul 13, 2018 at 11:41

1 Answer 1

2

You could try to explicitly ascribe the type parameter A to the pattern matched MyC, and eliminate the warnings by @unchecked:

trait MyT[A]

case class MyC[A](t: MyT[A])

def foo: MyC[_] = ???

def go[A](t: MyT[A]): Option[MyC[A]] = foo match {
  case m: MyC[A @unchecked] if (m.t == t) => Some(m)
  case _ => None
}
Sign up to request clarification or add additional context in comments.

6 Comments

Honestly, imo worse then my useless copy, because the @unchecked hurts me.
@allidoiswin Does it hurt even more than the fact that the compiler attempts to pattern match m against a MyC(`t`) without complaining? Or that the compiler allows invocations of == on values which aren't even necessary of same type?
well for the == it uses .equals no? I'm not sure what you mean with the first one about m vs MyC(`t`)
@allidoiswin Yes, == uses equals. I just don't see any great difference between the above @unchecked and something like def foobar[A](a: A, b: AnyRef): Option[A] = { if (a == b) Some(a) else None }. When using ==, it doesn't even require an @unchecked annotation for essentially same kind of "unsafe"-ish comparison.
@allidoiswin In the previous comment, from a == b you can conclude that b is of type A in the then-branch of the if. Likewise, if m.t == t, you can derive that m.t must be of type MyT[A], therefore m must be of type MyC[A]. The compiler doesn't see that, because it doesn't infer anything useful from the fact that m.t == t. This is not flow-sensitive typing, unfortunately...
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.