sdinesh94
sdinesh94

Reputation: 1178

How to make a list covariant :- scala

Consider SubFoo extends Foo . I have a construct like this

trait SomeTrait
{

def someFun(a : List[Foo], ...) -> List[Foo]
.
.
.
}

Now in my code I would like to do y:List[SubFoo] = someFun(List(x),...) where x:SubFoo and y should be of type List[SubFoo]. But I get the error message expected List(SubFoo), actual: List(Foo): - How do I do that with the following constraints:-

  1. I don't want to add a type parameter to SomeTrait ( like SomeTrait[+A]) because SomeTrait is used widely in our codebase without passing any types.

  2. I wouldn't like to change y:List[SubFoo] to List[Foo] . I am looking for a solution that does the required change where someFun is defined.

  3. The most obvious : do not change someFun to someFun(a : List[SubFoo], ...) -> List[SubFoo] . Nada

Let me know if there is a solution respecting the constraints or which at-least satisfies constraint-1.

Thanks

Upvotes: 0

Views: 213

Answers (1)

Nathan
Nathan

Reputation: 78409

As mentioned in the comments, variance is not your way. Lists are covariant.

Without knowing more about your problem, it sounds like you're trying get a sublist of Some[Foo], where the sublist consists entirely of SubFoos.

So given

sealed trait Foo
case class SubFoo(baz: Int) extends Foo
case class OtherSubFoo(bam: String) extends Foo

it sounds like you would want a list of

List(SubFoo(1), SubFoo(2), OtherSubFoo("a"), SubFoo(25)): List[Foo]

to be converted to

List(SubFoo(1), SubFoo(2), SubFoo(25)): List[SubFoo]

Type signatures exist for a reason. If you're trying to convert a List[Foo] to a List[SubFoo], you need your conversion function type to reflect that. Here is something you could potentially do:

trait SomeTrait {

  def someFun(foos: List[Foo]): List[SubFoo] = {

    val listOfSubFoos = foos.map {
      case (sub: SubFoo) => Some(sub)
      case _ => None
    }

    // now you have a list of type List[Option[SubFoo]],
    // and want to flatten it to a List[SubFoo]
    listOfSubFoos.flatten
  }
}

There would be other ways to structure it, but the core idea here is that you'd need a function that reduces a List[Foo] to a List[SubFoo]. You can't have a type List[Foo] and guarantee that every Foo is a SubFoo in the type system. If you need something like that, you'd most likely have to rethink your type hierarchy here.

Just remember the basic structure of inheritance. All SubFoos are Foos, but not all Foos are SubFoos.

Upvotes: 1

Related Questions