Returning a path-dependent type from a pattern match
Asked Answered
A

2

6

Given a heterogeneous type:

trait Request {
  type Result
}

trait IntRequest extends Request {
  type Result = Int
}

How can I make the Scala compiler happy about return a path dependent type based on a pattern match:

def test(in: Request): in.Result = in match {
  case i: IntRequest => 1234
  case _ => sys.error(s"Unsupported request $in")
}

The error:

<console>:53: error: type mismatch;
 found   : Int(1234)
 required: in.Result
         case i: IntRequest => 1234
                               ^
Aerograph answered 16/7, 2014 at 16:50 Comment(0)
A
8

The following works:

trait Request {
  type Result
}

final class IntRequest extends Request {
  type Result = Int
}

trait Service {
  def handle[Res](in: Request { type Result = Res }): Res
}

trait IntService extends Service {
  def handle[Res](in: Request { type Result = Res }): Res = in match {
    case i: IntRequest => 1234
    case _ => sys.error(s"Unsupported request $in")
  }
}

trait Test {
  def service: Service

  def test(in: Request): in.Result = service.handle[in.Result](in)
}

The compiler only eats it if one uses a final class, though?!

Aerograph answered 16/7, 2014 at 17:2 Comment(0)
S
0

I think it is better to use type class instead of dependent type pattern matching which needs to be override, so in this case, we dont need to redefine the Request inside the argument.

trait Request[T] {
  type Result = T
}

trait IntRequest extends Request[Int] {
}

def test[T](in: Request[T]): T = in match {
  case i: IntRequest => 123
  case _ => sys.error(s"Unsupported request $in")
}

test(new IntRequest {}) // 123

test(new Request[String] {}) // error
Srini answered 17/7, 2014 at 7:27 Comment(1)
Yes that would be a possibility. I am storing these in a Map however, so the type parameters are lost from the compiler point of view. That's why I like to use type members here.Aerograph

© 2022 - 2024 — McMap. All rights reserved.