Overriding a repeated class parameter in Scala? - scala

Section 4.6.2 of the Scala Language Specification Version 2.8 describes repeated parameters and says:
The last value parameter of a parameter section may be suffixed by “*”, e.g. (..., x:T*). The type of such a repeated parameter inside the method is then the sequence type scala.Seq[T].
However, this code:
abstract class A { def aSeq : Seq[A] }
class B(val aSeq : A*) extends A
class C extends B { override val aSeq :Seq[A] = Seq() }
give an error when compiled:
overriding value aSeq in class B of type A*; value aSeq has incompatible type
The compiler seems to indicate that A* is a distinct type from Seq[A].
Investigating the actual class of aSeq in this case shows it to be an instance of scala.collection.mutable.WrappedArray$ofRef but even the following code fails to compile with the same message:
class C extends B { override val aSeq = new ofRef(Array[A]()) }
So the question is, how do I go about overriding a member defined by a repeated parameter on the class?
In case you're wondering where this is coming from, that is exacly what scala.xml.Elem does to override the child method in scala.xml.Node.

Your issue can be summarized as:
scala> class A { def aSeq(i: Int*) = 1 }
defined class A
scala> class B extends A { override def aSeq(i: Seq[Int]) = 2 }
<console>:6: error: method aSeq overrides nothing
class B extends A { override def aSeq(i: Seq[Int]) = 2 }
The methods have different types. The spec says (emphasis mine):
The type of such a repeated parameter inside the method is then the sequence type scala.Seq[T]
As Int* and Seq[Int] aren't inside the method, this particular sentence does not apply.
Interestingly, this following code shows that the methods have different types before erasure but the same after:
scala> class G { def aSeq(i:Int*) = 1; def aSeq(i:Seq[Int]) = 2 }
<console>:5: error: double definition:
method aSeq:(i: Seq[Int])Int and
method aSeq:(i: Int*)Int at line 5
have same type after erasure: (i: Seq)Int
class G { def aSeq(i:Int*) = 1; def aSeq(i:Seq[Int]) = 2 }
So the question then becomes, why your B class can extend your A abstract class. There may be an inconsistency in the spec there. I don't know...
Edit: I re-read the spec and I can't figure out if there is anything related to repeated parameters and overriding. There does not seem to be anything about return type of repeated parameters, which is what you get for the val aSeq accessor method.
I think Mark's answer is a perfectly valid approach. In case you can't follow it, you can use the following workaround:
class C extends B {
private def aSeqHelper(a: A*) = a
override val aSeq = aSeqHelper(Seq[A](): _*)
}
So for instance:
import scala.xml._
class ElemX extends Elem("pref", "label", <xml a="b"/>.attributes, TopScope) {
private def childHelper(c: Node*) = c
override val child = childHelper(<foo/><bar/>: _*) }
Then:
scala> new ElemX
res4: ElemX = <pref:label a="b"><foo></foo><bar></bar></pref:label>

The copy method of xml.Elem uses it like this
def copy(
prefix: String = this.prefix,
label: String = this.label,
attributes: MetaData = this.attributes,
scope: NamespaceBinding = this.scope,
child: Seq[Node] = this.child.toSeq
): Elem = Elem(prefix, label, attributes, scope, child: _*)
So you can override the value in the B constructor
class C extends B(aSeq = Seq(): _*)
Or declare it as a parameter of the class C
class C(seq: Seq[A]) extends B(aSeq = seq: _*)
Though I am not sure it answers your question!

The spec never allowed for repeated types to leak out in this way. The compiler was changed in July 2011 to enforce this.
For more background, check out the comments in the ticket:
https://issues.scala-lang.org/browse/SI-4176

Related

Recursive call of `val` in scala trait?

I am trying to debug a scala program. I found a trait which behavior is similar to following:
trait A {
val a: Int = b
val b: Int = a
}
class B extends A
If we look at the trait there is cyclic assignment. val b is not even defined but used in definition of val a.
The above program compile successfully. Both a and b is zero. I tried to the same with variable type string and then value was null.
There is a third class that override val a similar to following
class C extends A {
override val a: Int = 10
}
Now if an instance of class C is created value a is 10 but val of b is still 0.
Finally, I checked further and instead of overriding a in the body of class, when I override it in constructor parameter similar to following:
class D(override val a: Int) extends A
val d = new D(10)
then both d.a and d.b is initialized to 10.
I wanted to understand that:
How definition of val in trait A is valid? In other words how scala interprets the val assignment in trait A
When a val that is defined in a trait is overridden in the body of a scala class what value is being used in the body of the trait if the same val is used in the trait elsewhere

In Scala Reflection, How to get generic type parameter of a concrete subclass?

Assuming that I have a Generic superclass:
class GenericExample[T](
a: String,
b: T
) {
def fn(i: T): T = b
}
and a concrete subclass:
case class Example(
a: String,
b: Int
) extends GenericExample[Int](a, b)
I want to get the type parameter of function "fn" by scala reflection, so I select and filter through its members:
import ScalaReflection.universe._
val baseType = typeTag[Example]
val member = baseType
.tpe
.member(methodName: TermName)
.asTerm
.alternatives
.map(_.asMethod)
.head
val paramss = member.paramss
val actualTypess: List[List[Type]] = paramss.map {
params =>
params.map {
param =>
param.typeSignature
}
}
I was expecting scala to give me the correct result, which is List(List(Int)), instead I only got the generic List(List(T))
Crunching through the document I found that typeSignature is the culprit:
* This method always returns signatures in the most generic way possible, even if the underlying symbol is obtained from an
* instantiation of a generic type.
And it suggests me to use the alternative:
def typeSignatureIn(site: Type): Type
However, since class Example is no longer generic, there is no way I can get site from typeTag[Example], can anyone suggest me how to get typeOf[Int] given only typeTag[Example]? Or there is no way to do it and I have to revert to Java reflection?
Thanks a lot for your help.
UPDATE: After some quick test I found that even MethodSymbol.returnType doesn't work as intended, the following code:
member.returnType
also yield T, annd it can't be corrected by asSeenFrom, as the following code doesn't change the result:
member.returnType.asSeenFrom(baseType.tpe, baseType.tpe.typeSymbol.asClass)
There are two approaches which I can suggest:
1) Reveal generic type from base class:
import scala.reflect.runtime.universe._
class GenericExample[T: TypeTag](a: String, b: T) {
def fn(i: T) = "" + b + i
}
case class Example(a: String, b: Int) extends GenericExample[Int](a, b) {}
val classType = typeOf[Example].typeSymbol.asClass
val baseClassType = typeOf[GenericExample[_]].typeSymbol.asClass
val baseType = internal.thisType(classType).baseType(baseClassType)
baseType.typeArgs.head // returns reflect.runtime.universe.Type = scala.Int
2) Add implicit method which returns type:
import scala.reflect.runtime.universe._
class GenericExample[T](a: String, b: T) {
def fn(i: T) = "" + b + i
}
case class Example(a: String, b: Int) extends GenericExample[Int](a, b)
implicit class TypeDetector[T: TypeTag](related: GenericExample[T]) {
def getType(): Type = {
typeOf[T]
}
}
new Example("", 1).getType() // returns reflect.runtime.universe.Type = Int
I'm posting my solution: I think there is no alternative due to Scala's design:
The core difference between methods in Scala reflection & Java reflection is currying: Scala method comprises of many pairs of brackets, calling a method with arguments first merely constructs an anonymous class that can take more pairs of brackets, or if there is no more bracket left, constructs a NullaryMethod class (a.k.a. call-by-name) that can be resolved to yield the result of the method. So types of scala method is only resolved at this level, when method is already broken into Method & NullaryMethod Signatures.
As a result it becomes clear that the result type can only be get using recursion:
private def methodSignatureToParameter_ReturnTypes(tpe: Type): (List[List[Type]], Type) = {
tpe match {
case n: NullaryMethodType =>
Nil -> n.resultType
case m: MethodType =>
val paramTypes: List[Type] = m.params.map(_.typeSignatureIn(tpe))
val downstream = methodSignatureToParameter_ReturnTypes(m.resultType)
downstream.copy(_1 = List(paramTypes) ++ methodSignatureToParameter_ReturnTypes(m.resultType)._1)
case _ =>
Nil -> tpe
}
}
def getParameter_ReturnTypes(symbol: MethodSymbol, impl: Type) = {
val signature = symbol.typeSignatureIn(impl)
val result = methodSignatureToParameter_ReturnTypes(signature)
result
}
Where impl is the class that owns the method, and symbol is what you obtained from Type.member(s) by scala reflection

Use cases of Covarient/Contravarient Annotations in Scala

In Scala, it's possible to specify whether a function or class is covarient or contravarient in the following manner
class Foo[+arg] // covarient
class Bar[-arg] // contravarient
What are the real world uses of this feature?
I know the compiler runs checks to make sure that the stated entity is actually covarient or otherwise, but what is the benefit of even adding such annotations?
The simplest case where your probably already using it without knowing it is the scala collections.
class A()
class B() extends A
case class Container[T](elem : T)
val listOfA:List[A] = List[B](new B(),new B())
val containerOfA:Container[A] = Container[B](new B()) // fails
Imagine you have the following hierarchy:
class A
class B extends A
Covariance. Covariant type can be used as return type:
class Foo[+arg] { // Covariant
def getArg(): arg = ???
}
def testCovariant(): Unit = {
val fooB = new Foo[B]
val foo: Foo[A] = fooB
// returns only objects of class derived from A
// so it is safe
val a: A = foo.getArg()
}
So you can use any of Foo[DerivedClass]where Foo[BaseClass] is used, because anywhere Foo[BaseClass].getArg is called BaseClass is expected as result and any DerivedClass can be returned and assigned to it.
Contravariance. Contravariant type can be used as method parameter type:
class Bar[-arg] { // Contravariant
def setArg(p: arg): Unit = ???
}
def testContravariant(): Unit = {
val barA = new Bar[A]
val bar: Bar[B] = barA
// can set B to bar which is actually Bar[A]
// but Bar[A].setArg(p: A) can accept any object
// of type derived from A
// so it is safe
bar.setArg(new B)
}
Again. You can use any of Bar[DerivedClass] where Bar[BaseClass] is used, because anywhere Bar[DerivedClass].setArg(p: DerivedClass) is called DerivedClass is expected as argument and any Bar[BaseClass] can be used in this context, because you can always pass DerivedClass to Bar[BaseClass].setArg(p: BaseClass).

Using private mutable collections of a covariant type

I have a covariant Scala type Thing[+B]. The implementation uses an internal mutable queue:
private val queue : AsyncQueue[B]()
AsyncQueue is a custom mutable queue implementation, with special properties which I can't easily implement in an immutable version. Because it's mutable, AsyncQueue is invariant. So I can't use it in my covariant type Thing.
Since queue is private, I can guarantee the correctness of my code: e.g. I won't try to assign queue to a reference of type Queue[Any]. How can I make this work, keeping Thing covariant in B, without using casts?
(The solution with casts is to declare an AsyncQueue[Object] and cast objects on enqueue/dequeue, which is very ugly.)
ETA: I understand type covariance, and I understand why I shouldn't be able to declare an AsyncQueue of a covariant type, or make AsyncQueue itself covariant. My question is how to design this code to avoid using casts everywhere.
You can make your member immune to the variance check by making it private[this], according to the spec.
scala> trait Thing[+A] { def next(): A }
defined trait Thing
expectedly,
scala> class Thingie[+A](implicit t: ClassTag[A]) extends Thing[A] { val as = mutable.ArrayBuffer.fill[A](10)(t.runtimeClass.newInstance.asInstanceOf[A]) ; private val it = as.iterator ; def next() = it.next() }
<console>:12: error: covariant type A occurs in invariant position in type => scala.collection.mutable.ArrayBuffer[A] of value as
class Thingie[+A](implicit t: ClassTag[A]) extends Thing[A] { val as = mutable.ArrayBuffer.fill[A](10)(t.runtimeClass.newInstance.asInstanceOf[A]) ; private val it = as.iterator ; def next() = it.next() }
but
scala> class Thingie[+A](implicit t: ClassTag[A]) extends Thing[A] { private[this] val as = mutable.ArrayBuffer.fill[A](10)(t.runtimeClass.newInstance.asInstanceOf[A]) ; private val it = as.iterator ; def next() = it.next() }
defined class Thingie
and
scala> class X
defined class X
scala> val xs = new Thingie[X]
xs: Thingie[X] = Thingie#49f5c307
scala> xs.next
res1: X = X#4816c290
You need #uncheckedVariance:
import scala.annotation.unchecked.uncheckedVariance
class A[T] {}
class B[+T] {
val a: A[T #uncheckedVariance] = null
}
Even the Scala standard library makes use of #uncheckedVariance, notably in allowing the invariant mutable collections to inherit from covariant traits.
If B is covariant in Thing[+B] then you will not be able to have B in a contravariant position in Thing, i.e.
def put(b:B) {...} // will fail to compile, can't use a covariant type in this position
But it is possible to make two interfaces for Thing, one where the type is used in covariant positions and one where it is used in contravarient positions, as in the following:
trait ThingProduce[+B] {
def get: B
}
trait ThingConsume[-B] {
def put(b: B)
}
class Thing[B] extends ThingConsume[B] with ThingProduce[B] {
private val queue = new scala.collection.mutable.Queue[B]
def put(b: B) {queue.enqueue(b)}
def get: B = queue.dequeue
def both(b: B): B = ???
}
So that with the class hierarchy:
class Animal
class Mammal extends Animal
class Dog extends Mammal
The following can be done:
val mammalThing: Thing[Mammal] = new Thing[Mammal]{}
val dogConsumer: ThingConsume[Dog] = mammalThing
val animalProducer: ThingProduce[Animal] = mammalThing
But not:
val dogConsumer: ThingConsume[Dog] = animalProducer
//or
val animalProducer: ThingProduce[Animal] = dogConsumer
Thus Thing[B] can be seen to be both covarient and contravariant, but only for certain members.

underscore "class needs to be abstract since method is not defined" error

With scala 2.10.2, I have a code that extends from class scala.swing.ListView[SomeClass] and I get this error:
src/some.scala:100: error: class Some_Renderer needs to be abstract, since method componentFor in class Renderer of type (list: scala.swing.ListView[_ <: SomeClass], isSelected: Boolean, focused: Boolean, a: SomeClass, index: Int)scala.swing.Component is not defined
private class Some_Renderer extends ListView.Renderer[SomeClass]
EDIT: "an extra Note" is actually the error here, as commented B[String] must be B[_].
EDIT: some real example follows
I have reproduced it as the following example, though with an extra Note:
scala> class B[A] { val m : Int = 0 }
defined class B
scala> abstract class C[A] { def f(l: B[_]):Int }
defined class C
scala> private class D extends C[String] { def f(l: B[String]):Int = { l.m } }
<console>:9: error: class D needs to be abstract, since method f in class C of type (l: B[_])Int is not defined
(Note that B[_] does not match B[String]: their type parameters differ)
private class D extends C[String] { def f(l: B[String]):Int = { l.m } }
EDIT: MWE
import scala.swing.{Component, Label, ListView}
class Test
object Retn extends Label { opaque = false }
private class TestRenderer extends ListView.Renderer[Test]
{
def componentFor(list: ListView[_], isSelected: Boolean, focused: Boolean, test: Test, index: Int): Component =
{
val retn = Retn
retn
}
}
<console>:9: error: class TestRenderer needs to be abstract, since method componentFor in class Renderer of type (list: scala.swing.ListView[_ <: Test], isSelected: Boolean, focused: Boolean, a: Test, index: Int)scala.swing.Component is not defined
private class TestRenderer extends ListView.Renderer[Test]
^
EDIT: MWE
I am only trying to patch that line of code, and do scala programming by no means.
Yet I do not understand what is the problem with this example. I found similar questions
but not with this underscore ("_") thing.
The example tries to provide an implementation for the abstract method f from class C[A].
Thank s for your comments or answers about this issue.
B[_] is an "existential type", but you can understand this as being roughly equivalent to B[Any].
The error message tells you Note that B[_] does not match B[String]: their type parameters differ. You wouldn't expect to be able to replace a List[Any] parameter with a List[String] in an overridden definition, would you? Because then what happens when you pass it a List[Int], which is also a bona fide List[Any] as required in the abstract class?
Solution: replace def f(l: B[String]):Int = ... with def f(l: B[_]):Int = ...
Edit: the problem with your MWE is that you've defined the TestRenderer class on one line, then you've written a code block delimited by { } on the next... this will be interpreted as you intend in normal code (although it's better to put the { at the end of the previous line) but since you're in the REPL the class definition is interpreted as soon as you hit return. Solution: either put the { at the end of the private class ... line or type in :paste to allow you to write the lot before it's interpreted.
... at least, I assume that's what your problem is. The MWE works fine for me in scala 2.10.0 REPL, although I get a slightly different error message if I just type in the private class ... line.
I'm not sure what the constraints are in your original case, but in your example, could you use B[_] instead of B[String] when you override f?
class D extends C[String] { def f(l: B[_]):Int = { l.m } }
The underscore in this case is an existential type, and can can be any subtype of Any. See here for more information on existential types in Scala.