How can I write a function have a polymorphic return type based on the type argument of its type parameter?

Daenyth

I have some code like this:

sealed trait Foo[A] {
  def value: A
}
case class StringFoo(value: String) extends Foo[String]
case class IntFoo(value: Int) extends Foo[Int]

I'd like to have a function which can use the A type given a subtype's type parameter.

// Hypothetical invocation
val i: Int = dostuff[IntFoo](param)
val s: String = dostuff[StringFoo](param)

I can't figure out how to declare dostuff in a way that works. The closest thing I can figure out is

def dostuff[B <: Foo[A]](p: Param): A

But that doesn't work because A is undefined in that position. I can do something like

def dostuff[A, B <: Foo[A]](p: Param): A

But then I have to invoke it like dostuff[String, StringFoo](param) which is pretty ugly.

It seems like the compiler should have all the information it needs to move A across to the return type, how can I make this work, either in standard scala or with a library. I'm on scala 2.10 currently if that impacts the answer. I'm open to a 2.11-only solution if it's possible there but impossible in 2.10

Ben Reich

As you might know, if you have a parameter of type Foo[A], then you can make the method generic in just A:

def dostuff[A](p: Foo[A]): A = ???

Since that might not always be the case, we can try to use an implicit parameter that can express the relationship between A and B. Since we can't only apply some of the generic parameters to a method call (generic parameter inference is all or nothing), we have to split this into 2 calls. This is an option:

case class Stuff[B <: Foo[_]]() {
    def get[A](p: Param)(implicit ev: B => Foo[A]): A = ???
}

You can check the types in the REPL:

:t Stuff[IntFoo].get(new Param) //Int
:t Stuff[StringFoo].get(new Param) //String

Another option along the same lines, but using an anonymous class, is:

def stuff[B <: Foo[_]] = new { 
    def apply[A](p: Param)(implicit ev: B <:< Foo[A]): A = ??? 
}

:t stuff[IntFoo](new Param) //Int

Here, I've used apply in stead of get, so you can apply the method more naturally. Also, as suggested in your comment, here I've used <:< in the evidence type. For those looking to learn more about this type of generalized type constraint, you can read more here.

You might also consider using abstract type members instead of generic parameters here. When struggling with generic type inference, this often provides an elegant solution. You can read more about abstract type members and their relationship to generics here.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

TypeScript type inference on function type parameter based on its argument type

Typescript: How can I get return type of function based on argument type?

How to have generics and constant function return type based on parameter

How to write a polymorphic function with a fixed type in one argument

How I can get return value based on argument type?

Can I change the return type based on a parameter

How can I type-hint a function where the return type depends on the input type of an argument?

How to Correctly Type Return type of function by its parameter

How can I make a function return its own type in C?

How to cast return type of function based on argument type?

How can I have custom type as return function in Swift?

TypeScript - function return type based on parameter type

Define return type of a function in dictionary based on its parameter in TypeScript

How can I mark the return type of a method based on the type of an argument in the object's constructor

Why can't I return a concrete type in a function that has a polymorphic return type?

TypeScript: how to have return type be the type of a parameter?

Trying to write a function that can accept an optional parameter and based on it's type, filter and return an icon

In PostgreSQL, How can I identify a type is composite based on its type Oid in C function?

Return type based on type argument

Deducing the function return type from its parameter's return type

How can I separate function type return type and arguments in template parameter

How can I pass a long type value into the parameter of a function with integer as the return type?

about sending argument into return that have function type

TypeScript mapping return type of a function from its argument type

Return type based on the type of a parameter

How can I change the return type of this function?

Define the return type of a function based on argument

How to infer the return type of a function based on an argument that contains a generic?

How to specify input function parameter type and return type when passing the function as an argument to another function?