1

This is a follow up question of Part1:

In scala, How to call generalised copy function of a case class if it is declared in a family outer type?

In Part 2, the definition of the family class become slightly more complex:


trait OuterSpike {

  class Thing

  case class Inner(v: Thing) {

    //    val outer = self
  }
}

object OuterSpike {

  {

    def cp(src: OuterSpike#Inner): OuterSpike#Inner = {
      src.copy()
    }

    def cp2[O <: OuterSpike](src: O#Inner): O#Inner = src.copy()

    val outer = new OuterSpike {
      val inner = this.Inner(new Thing)
    }
    cp(outer.inner)
  }
}

So the old trick no longer works, the above compiles with the following error:

[Error] /home/peng/git/shapesafe/graph-commons/src/main/scala/com/tribbloids/graph/commons/util/reflect/format/OuterSpike.scala:18: type mismatch;
 found   : com.tribbloids.graph.commons.util.reflect.format.OuterSpike#Thing
 required: _1.Thing where val _1: com.tribbloids.graph.commons.util.reflect.format.OuterSpike
[Error] /home/peng/git/shapesafe/graph-commons/src/main/scala/com/tribbloids/graph/commons/util/reflect/format/OuterSpike.scala:21: type mismatch;
 found   : O#Thing
 required: _1.Thing where val _1: O
two errors found

How to make it compile in this case?

tribbloid
  • 4,026
  • 14
  • 64
  • 103

2 Answers2

1

Seems you are refining OuterSpike with val inner which is dependent on outer instance

val outer = new OuterSpike {
  val inner = this.Inner(new Thing)
}

so try with dependent types instead of type projection

def cp(outer: OuterSpike)(src: outer.Inner): outer.Inner = {
  src.copy()
}
cp(outer)(outer.inner)
Mario Galic
  • 47,285
  • 6
  • 56
  • 98
  • Sometimes outer is not available. Imagine outer being defined out of the scope – tribbloid Apr 16 '21 at 23:13
  • @tribbloid Would `src` not have a reference to `outer`? (you had that in the previous version of your code, and I see a commented out field in the current question) – user Apr 16 '21 at 23:20
  • it is possible, but now you'll have to use an unsafe cast to coerce src again – tribbloid Apr 16 '21 at 23:28
0

Define a no-arg cp on the Inner perhaps?

trait OuterSpike { 
  class Thing
  case class Inner(v: Thing) {
     def cp() = copy()
  }
}

object OuterSpike {
    def cp[O <: OuterSpike](src: O#Inner) = src.cp()
    val outer = new OuterSpike {
      val inner = this.Inner(new Thing)
    }
    cp(outer.inner)
}

Alternatively, you can relax the definition of Inner a little bit:

case class Inner(v: OuterSpike#Thing)

If you define it like this, then def cp[O <: OuterSpike](src: O#Inner) = src.copy() works.

Dima
  • 39,570
  • 6
  • 44
  • 70
  • Works, but my question focus on solving it within scala's type system – tribbloid Apr 27 '21 at 00:36
  • 1
    @tribbloid I see ... And old, good XY-problem :) Good luck! – Dima Apr 27 '21 at 10:23
  • @tribbloid I added another option to the answer ... not sure if you consider that "within" or "outside" the type system :) – Dima Apr 27 '21 at 12:26
  • ok I'm not allowed to change the definition of OuterSpike, it is not my code. In reality the OuterSpike is actually scala reflection universe, yuge cluster of family polymorphism – tribbloid Apr 28 '21 at 20:19