EDIT 2 - BEGIN: What I have not verified, and I should have, was if the conversion of my example works for regular types. And it doesn’t neither. So, the title and all my post is surely wrong. Sorry for that. Should I delete it. EDIT 2 - END:
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
}
given refToReference[T]: Conversion[Ref[T], Reference] = identity;
// given 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)
}
What am I wrong?
Tried with scalaVersion
"3.1.3" and "3.2.1" with same result.