Recursive call of `val` in scala trait? - scala

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

Related

Scala: could not find implicit without val, but ambiguous implicits with val

Scala version: 2.12.4.
Let's say, there's one empty trait and one class with function, which accepts trait instance as implicit parameter:
trait I
class A {
def fa()(implicit i: I): Unit = {}
}
Let's define another class, which invokes this fa() function. We'll try to import I instance from its companion object:
class B(a: A) {
import B._
def fb(): Unit = { a.fa() }
}
object B {
private implicit object II extends I
}
But we face an error then!
error: could not find implicit value for parameter i: I
def fb(): Unit = { a.fa() }
^
Let's make implicit val then in class B:
class B(a: A) {
import B._
private implicit val ii = II
def fb(): Unit = { a.fa() }
}
Suddenly, we still face an error anyway:
error: ambiguous implicit values:
both value ii in class B of type => B.II.type
and object II in object B of type B.II.type
match expected type I
def fb(): Unit = { a.fa() }
^
Compiler doesn't see implicit in the first case, but sees the same implicit in the second case. Why?
How to import this implicit object from companion object?
This is an ordering issue with type inference. There are other similar questions, I don't know if there is an exact duplicate.
The issue is that when class B is type-checked, type inference hasn't yet run on object B. Using II in the body of class B in the second example triggers this type inference and makes it visible as an implicit I.
It can be solved by either placing the companion object before the class, or by giving explicit type to II, e.g.
object B {
private implicit val II: I = new I {}
}
See e.g. Why does this explicit call of a Scala method allow it to be implicitly resolved?

Two ways of (kind of) instantiating a trait in Scala

I know of two ways of making an anonymous class to instantiate a trait in Scala:
scala> trait SomeTrait {
| def aUsefulMethod = ()
| }
defined trait SomeTrait
scala> val instance1 = new SomeTrait{} // Method 1
instance1: SomeTrait = $anon$1#7307556f
scala> instance1.aUsefulMethod // Returns a Unit.
scala> object instance2 extends SomeTrait // Method 2
defined module instance2
scala> instance2.aUsefulMethod // Returns a Unit.
I can't think of a reason why they are not equivalent. Am I wrong?
I'm asking in part because I used to only know method 2 but now I see that method 1 is more common. So I'm wondering if I've been doing something wrong this whole time.
The first approach new Trait {} creates a new class-instance.
The second approach creates an object which is a Singleton.
One can see this in the REPL:
Define Trait
scala> trait Example {}
defined trait Example
New anonymous class
Each call to new will return a new Instance. One can see this that each object gets a new address.
scala> new Example{}
res0: Example = $anon$1#768debd
scala> new Example{}
res1: Example = $anon$1#546a03af
Object extending Trait
Here a singleton object is created once.
scala> object X extends Example
defined object X
scala> X
res2: X.type = X$#1810399e
scala> X
res3: X.type = X$#1810399e
Impact and comparison
Even if both approaches on the surface may seem similar they lead to different results.
scala> new Example{} == new Example{}
<console>:12: warning: comparing values of types Example and Example using `==' will always yield false
new Example{} == new Example{}
^
res4: Boolean = false
scala> X == X
res5: Boolean = true
Going even deeper
On the underlying structure both aproaches will lead to different *class files being generated when run on the JVM
Anonymous class
$ cat example.scala
object Example1 {
trait A
new A {}
}
$ scalac example.scala
$ ls *class
Example1$$anon$1.class Example1$A.class
Example1$.class Example1.class
$ cat example2.scala
object Example2 {
trait A
object X extends A
}
$ scalac example2.scala
$ ls *class
Example2$.class Example2$X$.class
Example2$A.class Example2.class
val instance1 = new SomeTrait{} is the same as
class X extends SomeTrait
val instance1: SomeTrait = new X
except the compiler creates the class X and gives it a name like $anon$1. If you then do val instance2 = new SomeTrait{} the compiler will notice it can reuse the same anonymous class. And object instance2 is also basically
class instance2$ extends SomeTrait {
override def toString = "instance2"
}
lazy val instance2 = new instance2$
except you can't create new instances of instance2$. So one difference is lazy instantiation: instance2 is only actually created when it's accessed (e.g. when you call instance2.aUsefulMethod), which makes a difference if the SomeTrait constructor throws an exception or has other side effects. Another is that you can use object at the top level (outside class, trait or object).

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.

Diverging implicit expansion error using SortedSet

I'm trying to use a code similar to
abstract class A[T] extends Ordered[A[T]] {
val att:Int
def compare(that:A[T]) =
if (this.att >= that.att)
1
else
-1
}
class B extends A[Int] {
val att = 1
}
When I try this in Scala 2.11 REPL
scala> import scala.collection.immutable.SortedSet
scala> SortedSet[B]()
I get the following error
<console>:11: error: diverging implicit expansion for type Ordering[B]
starting with method ordered in trait LowPriorityOrderingImplicits
SortedSet[B]()
How can I solve this?
You need an instance of the Ordering type class to create a SortedList. The ordered method mentioned in the error message will automatically create an Ordering[X] for any type X that's an Ordered[X].
Your B is not an Ordered[B], however—it only extends Ordered[A[Int]]. Ordered is invariant in its type argument, so Ordered[B] and Ordered[A[Int]] have essentially nothing to do with each other.
You can address this issue with F-bounded polymorphism:
abstract class A[T, S <: A[T, S]] extends Ordered[S] {
val att: Int
def compare(that: S)=
if (this.att >= that.att)
1
else
-1
}
class B extends A[Int, B] {
val att = 1
}
Now B extends Ordered[B] and you can create the sorted set.
Alternatively, you could use your original code and just create a SortedSet[A[Int]]. It's a much better idea to avoid Ordered altogether, though, and just define the Ordering type class instance directly.

Overriding a repeated class parameter in 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