Type alias behaviour

Hello everybody!

Give me some help when aliasing types.

Shouldn’t this work? I would like a clean syntax for defining routes


trait RouteRequest

trait RouteResponse

type Req <: RouteRequest
type Resp <: RouteResponse

type RouteCallback = Req => Resp
type RouteAsyncCallback = Req => Resp => Unit

type RouteDispatcher = RouteCallback | RouteAsyncCallback

case class Request() extends RouteRequest()

case class Response() extends RouteResponse()

def route(path: String, dispatch: RouteDispatcher) = ???

route("/") { (r: Request) => Response() } // error!

[error] 92 |  route("/", (r: Request) => Response() ) 
[error]    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
[error]    |             Found:    Request => Response
[error]    |             Required: RouteDispatcher

Even if I change it like this, the error remains.

def route(path: String, dispatch: RouteCallback) = ???

If I change it like this it works

def route[T1 <: RouteRequest, T2 <: RouteResponse](path: String, dispatch: T1 => T2) = ???

Function parameter types are contravariant, so even though Request is a subtype of RouteRequest, Request => Response is not a subtype of RouteRequest => RouteResponse (or RouteCallback).

2 Likes

Contravariance is so counter-intuitive for humans, that a PhD in programming languages literally had to jump up and down to explain it to students (near end of video): https://www.coursera.org/learn/programming-languages-part-c/lecture/6tSBR/function-subtyping

2 Likes

Interesting, but he could further clarify the point home by setting his hair on fire and screaming. :rofl:

1 Like

Thanks for the answers. To complement, taken from stackoverflow Contravariance vs Covariance in Scala - Stack Overflow

A type can be contravariant when it does call methods on the type that it is generic over.
If the type needs to return values of the type it is generic over, it cannot be contravariant.

A type can be contravariant when it does call methods on the type that it is generic over.
If the type needs to return values of the type it is generic over, it cannot be contravariant.

Functions are the best example of contravariance
(note that they’re only contravariant on their arguments, and they’re actually covariant on their result).

1 Like