scala - using asInstanceOf with Generics - scala

I'm having compilation issues with generics. The code compiles fine when I use asInstanceOf. I want to get rid of asInstanceOf.
I saw some other questions related to the usage of asInstanceOf, but I didn't help me.
trait RoundRobin[R <: Resource, F[_] <: mutable.ListBuffer[_]] {
self: RoundRobin[R, F] =>
// some public functions
private def overrideMutableResourceList(original: F[R], updated: F[R]): F[R] = {
val tempPool = original.asInstanceOf[mutable.ListBuffer[R]]
original.indices.foreach(i => {
val e = updated(i).asInstanceOf[R]
tempPool.update(i, e)
})
tempPool.asInstanceOf[F[R]]
}
When I remove the asInstanceOf from tempPool.asInstanceOf[F[R]] I get the below error
[error] /Users/...../RoundRobin.scala:108: type mismatch;
[error] found : tempPool.type (with underlying type scala.collection.mutable.ListBuffer[R])
[error] required: F[R]
[error] tempPool
[error] ^
[error] one error found
[error] (clustering/compile:compileIncremental) Compilation failed
[error] Total time: 3 s, completed Oct 3, 2017 2:53:34 AM
This issue happens also for the line original.asInstanceOf[mutable.ListBuffer[R]]
What is the reason for this issue?
How can I avoid using asInstanceOf ?
Thanks

There's no relationship between F[A] and ListBuffer[A], only that ∀A∃B F[A] <: ListBuffer[B]. This is important:
type ConstLBInt[A] = ListBuffer[Int]
val x: RoundRobin[Resource, ConstLBInt] = ??? // Legal
// Tries to manipulate ListBuffer[Int]s as if they were ListBuffer[Resources]s
Change the declaration of your type to
trait RoundRobin[R <: Resource, F[A] <: mutable.ListBuffer[A]]
// ! !
This forces ∀A F[A] <: ListBuffer[A], so that e.g. the updated: F[R] in overrideMutableResourceList is known to be a ListBuffer[R].
There are probably other parts of the class that will be simplified by this.

Related

Why does Scala fail to find implicit view when one is available?

Any idea why this fails to find the implicit view?
// Making B invariant fixes it.
sealed trait ImplicitlyStable[A, +B]
object ImplicitlyStable {
implicit def convertibleToStable[A, B](implicit
aToB: A => B,
// Removing bToB fixes it.
bToB: ImplicitlyStable[B, B]
): ImplicitlyStable[A, B] = ???
}
object Test {
def testConvertibleToStable[A, B](implicit
aToB: A => B,
bToB: ImplicitlyStable[B, B]
): ImplicitlyStable[A, B] =
implicitly[ImplicitlyStable[A, B]]
}
It fails with:
[error] !I e: ImplicitlyStable[A, B]
[error] ImplicitlyStable.convertibleToStable invalid because
[error] !I aToB: A => B
[error] No implicit view available from A => B.
[error]
[error] implicitly[ImplicitlyStable[A, B]]
[error] ^
[error] one error found
It says No implicit view available from A => B which is clearly not true as there is an implicit parameter of that type.
Is this one of those situations where it is inferring Nothing for B? If so, why would it do that?
If I add:
private def unexpected: Nothing = sys.error("Unexpected invocation")
implicit def nothingStableAmbig1[A]: ImplicitlyStable[Nothing, A] = unexpected
implicit def nothingStableAmbig2[A]: ImplicitlyStable[Nothing, A] = unexpected
implicit def nothingStableAmbig3[A]: ImplicitlyStable[A, Nothing] = unexpected
implicit def nothingStableAmbig4[A]: ImplicitlyStable[A, Nothing] = unexpected
Then it fails with:
[error] ambiguous implicit values:
[error] both method nothingStableAmbig3 in object ImplicitlyStable of type [A]ImplicitlyStable[A,Nothing]
[error] and method nothingStableAmbig4 in object ImplicitlyStable of type [A]ImplicitlyStable[A,Nothing]
[error] match expected type ImplicitlyStable[A,B]
[error] implicitly[ImplicitlyStable[A, B]]
[error] ^
So sure enough, it is inferring Nothing, but why?
It seems like this might be a bug in Scala 2 that has been fixed in Scala 3.
I raised an issue for it.
I'm not sure if there is any more reasoning behind why it is inferring Nothing. If anyone knows then that would be great.

Family polymorphism with ScalaTest

I'm trying to achieve something with ScalaTest and based on C. Hosrtmann's "Scala for the impatient" I think this is related to "Family polymorphism". Apparently I don't understand something about Scala's type system, so I fail.
To cut the long story short, this is what I'm trying to do.
I have a base (production) trait:
trait MaxPQ[Key] {
implicit protected val cmp: Ordering[_ >: Key]
...
def insert(v: Key): Unit
def max(): Key
def delMax(): Key
...
}
then there is a number of implementations (that use either a backing tree or an array).
In tests I want to create an abstract structure which would allow to test any implementation for three Ordered Keys: Char, Int, Double.
First I've written two behaviors (for empty and non-empty priority queues). Here's a snippet:
trait MaxPQBehaviours {
// underlying tests spec
self: BaseSpec =>
def nonEmptyMaxPQ[T <: Ordered[T], ImplLà <: MaxPQ[T]](instanceSupplier: () => ImplLà, sortedInput: List[T]): Unit = {
...
behavior of "size"
it should s"be equal to ${sortedInput.size}" in {
val instance = instanceSupplier()
instance.size() shouldEqual sortedInput.size
}
behavior of "max"
it should s"return the expected $max" in {
val instance = instanceSupplier()
instance.max() shouldEqual max
}
...
Finally to add a last layer of abstraction I'm adding a BaseMaxPQSpec that mixes-in the above MaxPQBehaviours and calls its behaviors for three abstract MaxPQ types. Here I'only provide example for Char:
trait BaseMaxPQSpec extends BaseSpec with MaxPQBehaviours {
type CharMaXPQ <: MaxPQ[Char]
def charMaxPQ: CharMaXPQ
val sortedCharsList: List[Char] = List[Char]('C', 'b', 'd', 'a', 'z').sorted
it should behave like nonEmptyMaxPQ(() => charMaxPQ, sortedCharsList)
}
And this is where compiler spits this at me:
[error] ~/Algorithms/Chapter 2 Sorting/algorithms2_1/src/test/scala/ca/vgorcinschi/algorithms2_4/BaseMaxPQSpec.scala:18:25: inferred type arguments [Char,BaseMaxPQSpec.this.CharMaXPQ] do not conform to method nonEmptyMaxPQ's type parameter bounds [T <: Ordered[T],ImplLà <: ca.vgorcinschi.algorithms2_4.MaxPQ[T]]
[error] it should behave like nonEmptyMaxPQ(() => charMaxPQ, sortedCharsList)
[error] ^
[error] ~/Algorithms/Chapter 2 Sorting/algorithms2_1/src/test/scala/ca/vgorcinschi/algorithms2_4/BaseMaxPQSpec.scala:18:42: type mismatch;
[error] found : () => BaseMaxPQSpec.this.CharMaXPQ
[error] required: () => ImplLà
[error] it should behave like nonEmptyMaxPQ(() => charMaxPQ, sortedCharsList)
[error] ^
[error] ~/Algorithms/Chapter 2 Sorting/algorithms2_1/src/test/scala/ca/vgorcinschi/algorithms2_4/BaseMaxPQSpec.scala:18:56: type mismatch;
[error] found : List[Char]
[error] required: List[T]
[error] it should behave like nonEmptyMaxPQ(() => charMaxPQ, sortedCharsList)
[error] ^
[error] three errors found
[error] (Test / compileIncremental) Compilation failed
[error] Total time: 12 s, completed Feb 15, 2020 6:21:35 PM
What is the correct way to set-up my testing framework? Please don't hesitate to ask for details, clarifications.
Given
nonEmptyMaxPQ(() => charMaxPQ, sortedCharsList)
type inference deduces type T = Char because the type of charMaxPQ is MaxPQ[Char], thus
T <: Ordered[T]
becomes Char <: Ordered[Char]
which certainly is not true. Perhaps try specifying Ordering like so
def nonEmptyMaxPQ[T: Ordering, Impl <: MaxPQ[T]](instanceSupplier: () => Impl, sortedInput: List[T])
Note the difference between upper bound T <: Ordered[T] and context bound T: Ordering.

Using type lambdas together with higher-kinded types in Scala: how to get compiler to infer types correctly?

Suppose I have trait that represents something like a polymorphic function, e.g.:
trait Func[A[X, Y]] {
def apply[X, Y](a: A[X, Y]): A[X, Y]
}
Now I want to use my trait as a non-polymorphic function by passing type lambda as argument:
type single[T] = { type t[X, Y] = T }
val aInstance: Func[single[String]#t] =
new Func[single[String]#t] {
def apply[X, Y](a: String): String = ???
}
Now I have method test which does some useful things with func, e.g.
def test[A[X, Y]](f: Func[A]): Unit = ???
And I want to invoke test with aInstance without specifying type parameters by hand:
test(aInstance)
Unfortunately, this code does not compile (but test[single[String]#t](aInstance) does) with error messages:
[error] /test.scala:16:3: no type parameters for method test: (f: Func[A])Unit exist so that it can be applied to arguments (Func[[X, Y]String])
[error] --- because ---
[error] argument expression's type is not compatible with formal parameter type;
[error] found : Func[[X, Y]String]
[error] required: Func[?A]
[error] test(aInstance)
[error] ^
[error] /test.scala:16:8: type mismatch;
[error] found : Func[[X, Y]String]
[error] required: Func[A]
[error] test(aInstance)
[error] ^
[error] two errors found
My question is: how can I modify these declarations to allow compiler to infer all required types automatically?
To those wondering why I declared Func as having [X, Y] but never used them in actual code there is a more real-world and less abstract example:
object GenericTest {
trait Item { def name: String }
class ItemA extends Item { def name: String = "a" }
class ItemB extends Item { def name: String = "b" }
trait MapFn[-A[X <: Item], +B[X <: Item]] {
def apply[X <: Item](data: A[X]): B[X]
}
case class ItemsCollection[C[A <: Item]](a: C[ItemA], b: C[ItemB]) {
def map[D[A <: Item]](f: MapFn[C, D]): ItemsCollection[D] =
ItemsCollection(f(a), f(b))
}
// sometimes we want to store sequences...
val itemSeq = ItemsCollection[Seq](Seq(new ItemA), Seq(new ItemB))
// or transform them:
val itemSet = itemSeq.map(new MapFn[Seq, Set] {
override def apply[X <: Item](data: Seq[X]): Set[X] = data.toSet
})
// but one day we wanted to store just objects without any item-specific types... e.g. names:
type single[X] = { type t[A] = X }
val itemNames = itemSeq.map(new MapFn[Seq, single[String]#t] {
override def apply[X <: Item](data: Seq[X]): String = data.head.name
})
/*
[error] test.scala:28:27: no type parameters for method map: (f: MapFn[Seq,D])ItemsCollection[D] exist so that it can be applied to arguments (MapFn[Seq,[A]String])
[error] --- because ---
[error] argument expression's type is not compatible with formal parameter type;
[error] found : MapFn[Seq,[A]String]
[error] required: MapFn[Seq,?D]
[error] val itemNames = itemSeq.map(new MapFn[Seq, single[String]#t] {
[error] ^
[error] test.scala:28:31: type mismatch;
[error] found : MapFn[Seq,[A]String]
[error] required: MapFn[Seq,D]
[error] val itemNames = itemSeq.map(new MapFn[Seq, single[String]#t] {
[error] ^
[error] two errors found
*/
}
Referring to your GenericTest, there is no way to get Scala to infer that shape, because of this closed-but-unfixed bug.
One thing you can do is try to adapt the technique of Unapply, using implicit resolution to determine the likely candidate for D. This will probably entail defining your own typeclass and instances, not using the ones Scalaz supplies, and possibly changing how MapFn is declared to be more suitable for this pattern. Make sure that the instance that gives you single has the lowest priority, as it can always be used (every T is an F[T] if F = Id).
If you control the definition of MapFn, you may also move the B type parameter to a type member. Then the signature of map becomes
def map(f: MapFn[C]): ItemsCollection[f.B] =
You can add a subclass to MapFn that moves the type member back to a parameter for ease of MapFn creation.

Why does implicit type conversion from Int to UInt not work?

I'm trying to learn chisel3, and I also try to be able to use implicit type conversion from Int to UInt in specific case.
Following is my code.
package VecTest
import chisel3._
import scala.language.implicitConversions
object VecTestMain extends App {
Driver.execute(args, () => new VecTest)
}
object VecTest {
implicit def int2UInt(x: Int) = new fromtIntToLiteral(x).U
}
class VecTest extends Module {
import VecTest._
val io = IO(new Bundle{
val in = Input(UInt(1.W))
val out = Output(UInt(8.W))
})
val v = VecInit(0x20, 0x30)
io.out := v(io.in)
}
I expected scala compiler will try to convert two values in VecInit from Int to UInt, but compiler reports error like below.
[error] /src/directory/this/code/VecTest/VecTest.scala:23:11: inferred type arguments [Int] do not conform to macro method apply's type parameter bounds [T <: chisel3.core.Data]
[error] val v = VecInit(0x20, 0x30)
[error] ^
[error] /src/directory/this/code/VecTest/VecTest.scala:23:19: type mismatch;
[error] found : Int(32)
[error] required: T
[error] val v = VecInit(0x20, 0x30)
[error] ^
[error] /src/directory/this/code/VecTest/VecTest.scala:23:25: type mismatch;
[error] found : Int(48)
[error] required: T
[error] val v = VecInit(0x20, 0x30)
[error] ^
[error] three errors found
First, I thougth compiler can not get int2UInt(implicit type converter function in object VecTest) because of out of scope. However, when I fixed the code like below, it will work.
val v = VecInit(int2UInt(0x20), int2UInt(0x30))
I also make a hypotheses that chisel3 already has a implicit type converter like my converter, but that is probably not correct.
Where is my misstakes?
I think the closest answer is the second answer here.
In short, because VecInit is parameterized with [T <: Data] the entire space of T is not searched to see what Implicit conversions might return a T.
You can manually force the proper implicit like this
val v = VecInit[UInt](0x20, 0x30)
I would like to point out that earlier versions of chisel allowed Int parameters on VecInit and its allies. Our experience was that requiring specific Hardware Types was less error prone and easier to read. Adding .U to the numbers is fairly low boilerplate overhead.
val v = VecInit(0x20.U, 0x30.U)

Scala: Equivalence of path-dependent types

How do I get around with equivalence of two path-dependent types that I know are the same but the compiler does not?
Using Scala 2.10.0 M7 I am trying to convert an AST from one universe to another.
case class MacroBridge(context: Context) {
def toMacroTree(tree: treehugger.forest.Tree): context.universe.Tree = ???
def fromMacroTree(tree: context.universe.Tree): treehugger.forest.Tree = ???
}
Within a macro implementation, I can use it as:
val bridge = treehugger.MacroBridge(c)
def fromMacroTree(tree: c.universe.Tree): Tree = bridge.fromMacroTree(tree)
However, this results to a compiler error:
[error] /scalamacros-getting-started/library/Macros.scala:21: type mismatch;
[error] found : c.universe.Tree
[error] required: bridge.context.universe.Tree
[error] possible cause: missing arguments for method or constructor
[error] def fromMacroTree(tree: c.universe.Tree): Tree = bridge.fromMacroTree(tree)
In the above code c is clearly the same value as bridge.context, but maybe because it's a value type checker cannot check it. Putting generalized type constraint did not help:
def fromMacroTree[A](tree: A)(implicit ev: A =:= context.universe.Tree): Tree =
In the macro this still resulted to an error:
[error] /scalamacros-getting-started/library/Macros.scala:21: Cannot prove that c.universe.Tree =:= bridge.context.universe.Tree.
[error] def fromMacroTree(tree: c.universe.Tree): Tree = bridge.fromMacroTree(tree)
I need the access to context.universe so I can get to other dependent types like TermName. Is there a better work around besides casting?:
def fromMacroTree(tree: c.universe.Tree): Tree =
bridge.fromMacroTree(tree.asInstanceOf[bridge.context.universe.Tree])
I could the following make to work:
case class MacroBridge[C <: Context](context: C) {
def fromMacroTree(tree: context.universe.Tree): context.universe.Tree = ???
}
trait MB {
def meth(c: Context) {
val bridge = MacroBridge[c.type](c)
def fromMacroTree(tree: c.universe.Tree): c.universe.Tree =
bridge.fromMacroTree(tree)
}
}
I had nearly the same problem some time ago.