Function should return same type

F.e. I have
type MyType = Animal => Animal

And

enum Animal:
case Dog(i: Int)
case Cat(a: String)

Is it possible to add restriction to MyType to be sure that input’s type = output’s?

val impl: MyType = …

updatedCat = impl(cat)

updatedDog = impl(dog)

Without seeing what should the impl be it is hard to say exactly, but you can define MyType as:

type MyType[T] = T => T

or

type MyType[T <: Animal] = T => T

Here is one way possible way to write this so that everything typechecks:

type MyType[T] = T => T


enum Animal:
  case Dog(i: Int)
  case Cat(a: String)

def impl[T]: MyType[T] = x => x

val cat: Animal.Cat = Animal.Cat("A")
val dog: Animal.Dog = Animal.Dog(1)

val updatedCat: Animal.Cat = impl(cat)

val updatedDog: Animal.Dog = impl(dog)

Note: without explicit type even type of val cat = Animal.Cat("A") is Animal, not Animal.Cat.

@OndrejSpanel val or def impl is

def impl(animal: Animal): Animal =
animal match:
case Cat(a) => Cat(a +“1”)
case Dog(i) => Dog(i + 1)

It will work with explicit .asInstanceOf[T], but maybe there is some other solution to get proper type. Imagine

for {
cat ← createCat()
updatedCat ← impl(cat)
res ← funcThatAcceptOnlyCat(updatedCat)
}

Because of this I need the compiler to understand that there will be type Cat for updatedCat

You have two options.

  1. Do this:
def impl[A <: Animal](animal: A): A =
  animal match
    ...

And then on each case you must do a .asInstanceOf[A]

  1. Or use a typeclass. Since, this is in essence the “return the same type” problem: Scala FAQ | Scala Documentation

If you wonder why the cast is necessary in the match case, is because as far as the compiler is concerned that animal matched Cat at runtime, doesn’t mean that the type was Cat. It could have been Animal or it could have been something like Cat | Dog or it could have been something like Cat & Foo, etc.

See also tpolecat’s seminal article on this subject, which helps motivate why type classes tend to be the right answer when you wind up with this problem.

2 Likes

Thanks guys!

It is possible to return the same time as on the input, using generics, two major techniques are type-classes or f-bound polymorphism, also called recursive types.

In your case though it seems you do not have the exact type (Cat or Dog) on the input compile-time, therefore I am not sure what compile-time type of the result do you expect.

Doing the same runtime is trivial, and your code using match already does it.

Perhaps if you show how do you consume the result of impl, so that we can see where is your asInstanceOf now, it might be possible to suggest a way.