Below is a specific instance of a kind of situation that I sometimes encounter with parameterized types. Basically, there are type parameters that I know are compatible, but I don't know how to prove that to some parts of the code.
I'm writing a request router that maps urls to handler functions. Below is some simplified code. I create a List[Route] where a Route is basically a UrlMatcher, Function pair.
class Route[A](matcher: UrlMatcher[A], handler: HandlerFunction[A]) abstract class UrlMatcher[A] { def match(url: String): Option[A] // None if no match The type parameter A is for the "arguments" that the matcher might extract from the URL. They would be passed to the handler function. For example, a UrlMatcher[Int] that sees a URL path like "/users/123" could pass 123 to a getUser(id: Int) function. The router might look like:
val routes = ArrayBuffer[Route[_]] def callHandler(url: String) { for (r <- routes) { val args = r.matcher.matchUrl(url) if (args.isDefined) r.handler(args.get) // <--- error here } The problem is that I get type mismatch errors because I don't know how to tell it the two types are the same.
type mismatch; found: args.type (with underlying type Option[Any]) required: _$1 I know I can redesign it so that Route has a method like matchAndCall, but I'd like to keep this logical flow if possible.
Update/Edit
I don't fully understand existential types, but I tried this...
val routes = ArrayBuffer[T forSome { type T }]() And it removed the mismatch error above. However, I have another one where I was inserting into the ArrayBuffer.
def route[P](matcher: UrlMatcher[P], handler: Handler[P]): AbstractRoute = { val route = new Route(matcher, handler) otherRoutes.append(route) // error here route } Now the error is...
type mismatch; found : Route[P] required: Route[T forSome { type T }] Note: P <: T forSome { type T }, but class Route is invariant in type P. You may wish to define P as +P instead. (SLS 4.5) Why is P incompatible with T, since their are no constraints on T?