The intention of the Sheet1
class is to store values in a typeless container but operate with them type-safely.
class Sheet1 {
opaque type Ref[X] = Int;
private val cells: ArrayBuffer[Any] = ArrayBuffer.empty;
def addCell[A](a: A): Ref[A] = {
val ref = cells.size;
cells.addOne(a);
ref
}
def update(map: Map[Ref[?], Any]): Unit = // does not compile: unreducible application of higher-kinded type Ref to wildcard arguments
map.foreachEntry { (k, v) => cells(k) = v }
}
But the compiler grumbles with “unreducible application of higher-kinded type Ref
to wildcard arguments”. I googled that message and nothing I found helped me to solve the problem.
EDIT - BEGIN: Now I know that I can avoid that message replacing the wildcard with a type parameter.
def update[X](map: Map[Ref[X], Any]): Unit
at the cost of making Ref
covariant (which it should not be). But suppose you preferred to face it with implicit conversion as follows.
EDIT - END
So, I tried another approach: add a plain opaque type Reference
, replace the the wildcard opaque type Ref[X]
of the method signature with the plain opaque type Reference
, and add an implicit conversion between them.
class Sheet2 {
opaque type Reference = Int;
opaque type Ref[X] = Reference;
private val cells: ArrayBuffer[Any] = ArrayBuffer.empty;
def addCell[A](a: A): Ref[A] = {
val ref = cells.size;
cells.addOne(a);
ref
}
implicit def refToReference[T]: Conversion[Ref[T], Reference] = identity;
// implicit def refMapToReferenceMap[K, V]: Conversion[Map[Ref[K], V], Map[Reference, Any]] = identity
def update(map: Map[Reference, Any]): Unit = map.foreachEntry { (k, v) => cells(k) = v }
}
Which avoids the “unreducible application of higher-kinded type Ref to wildcard arguments” problem and compiles fine but, when I try to use it, the implicit conversion does not work:
object User {
val sheet = new Sheet2;
import sheet.*
val listRef: Ref[List[Int]] = sheet.addCell(List(1,2,3));
import scala.language.implicitConversions;
import sheet.refToReference; // not necessary but just in case
sheet.update(Map((listRef: Reference) -> List(3,2,1))); // Works using type ascription.
sheet.update(Map(refToReference(listRef) -> List(3,2,1))); // Works using the converter explicitly.
val x = Map(refToReference(listRef) -> List(3,2,1))
sheet.update(x); // Works using an intermediate variable but only if the conversion `refMapToReferenceMap` is uncommented.
sheet.update(Map(listRef -> List(3,2,1))); // Trying implicit conversion fails with: Found: (sheet.Ref[List[Int]], List[Int]); Required: (sheet.Reference, Any)
}
Tried with scalaVersion
“3.1.3” and “3.2.1” with same result.