illegal cyclic reference involving object scala and case class - scala

Why do I get an error saying illegal cyclic reference? I thought objects in scala are like singleton and act as a container and cannot be instantiated. Why it is cyclic? How to fix this error without moving case class Baz out of object Bar?
trait Foo[T]
object Bar extends Foo[Bar.Baz] {
case class Baz()
}
Error:
illegal cyclic reference involving object Bar
object Bar extends Foo[Bar.Baz] {

Related

What is the type of a companion object in Scala?

For example, I have:
class AClass {
}
object AClass{
}
.....
println(AClass.getClass.toString)
println((new AClass).getClass.toString)
println(AClass.toString)
println((new AClass).toString)
When I tried to print out the types of the class and the companion object,I got:
class tmp.AClass$
class tmp.AClass
tmp.AClass$#44a664f2
tmp.AClass#7f9fcf7f
I think the type of an instance of the class AClass is AClass.
What is the type of the companion object AClass? What is the dollar symbol's meaning in AClass$?
What is the type of the class AClass? Can I use the class AClass directly without make an instance of it?
The dollar sign is a valid part of a class name on the JVM. You will see it commonly used in generated classes. So AClass$ is just a normal class name with nothing special about it.
Of course that's only it's run-time type that it gets compiled to. Within scala code, the type of the companion to AClass is AClass.type

Scala traits defining other traits

I ran into an interesting scenario in Scala. It seems then I have a base trait that defines other traits, the implementation cannot find the base trait not matter what.
I created this base trait simple for convenience that I don't need to redefined these traits on every implementation. Do anyone know why this doesn't work?
object Base {
trait Create
trait Delete
}
trait BaseTrait {
trait Create extends Base.Create
trait Delete extends Base.Delete
}
object Implementation extends BaseTrait
object Something {
class SomeClass extends Implementation.Create //The trait is not defined.
}
Update:
The question has been cleared up a bit so that its more precise. The solution as #BrianHsu pointed out is that trait cannot be inherited.
This block of code is fine:
object Base {
trait Event
trait Command
}
The following block will run into to trouble:
trait BaseTrait {
trait Event extends Event
trait Command extends Command
}
But Scala compiler says it very clearly.
test.scala:7: error: illegal cyclic reference involving trait Event
trait Event extends Event
^
test.scala:8: error: illegal cyclic reference involving trait Command
trait Command extends Command
Of course you cannot do this, just like you could not do the following in Java:
class HelloWorld extends HelloWorld
You have to specify that what you extend is actually Base.Event / Base.Command, so it will only work if you write it as:
trait BaseTrait {
trait Event extends Base.Event
trait Command extends Base.Command
}
Another problem in your code it the last Something object, it does not make sense at all:
object Something {
Implementation.Event
Implementation.Commannd
}
So compiler give you a clear error message:
test.scala:14: error: value Event is not a member of object Implementation
Implementation.Event
^
test.scala:15: error: value Commannd is not a member of object Implementation
Implementation.Commannd
It's quite obvious, an trait in Scala is much like interface in Java, you should not use it as it is a field.

Calls to supertype methods in traits allowed with `extends` but not with self-types

Consider:
trait SuperBar { def superBarMethod = ??? }
trait Bar extends SuperBar
trait FooWithSelfType { this: Bar =>
super.superBarMethod // error: value superBarMethod is not a member of AnyRef
}
trait FooWithExtends extends Bar {
super.superBarMethod
}
Is this limitation due to some underlying implementation shortcoming, or it's actually designed this way for a reason?
The way I see this is that if this is known to be of type Bar, and Bar is known to be a subtype of SuperBar, then invoking any SuperBar methods on this should be allowed.
FooWithSelfType might know that it is a Bar, but it's not actually part of FooWithSelfType's inheritance hierarchy, so it doesn't have access to super except for the super that is explicitly part of its inheritance hierarchy. If you had
trait Baz extends SuperBaz { this : Bar =>
/* ... */
}
how would you know to what super refers if both SuperBaz and SuperBar were possibilities?
Self-type says that the current trait should be mixed into is at most the type you are using as a self-type. Meaning that all subtypes of that given type can mix the current trait. With that in mind, super only refers to the class/trait that the current trait is a sub class/trait of.
I have to say that I ran into this thought not that long ago, and I think this could be a weakness, I mean we could imagine that the compiler could look up both methods in the superclass and those in the self-type's superclass.

Ambiguous reference to overloaded definition with inherited inner class, scala

So here is the problematic code:
trait World {
type State
def dynamics(s: State): State
// ...
}
trait GridWorld extends World {
class State {...} // concrete
def dynamics(s: State) = s // concrete
// some other staff still abstract
}
trait SimpleGridWorld extends GridWorld {
class State extends super.State {...} // concrete
def foo {dynamics(new State)} // compiler error
}
The compiler says that, dynamics in both World and GridWorld match the signature. However, in World it is abstract and then implemented in GridWorld, so it seems to me that it is clear that I am calling GridWorld.this.dynamics.
Another thing I noticed is that, if I remove the extends super.State in SimpleGridWorld, everything works fine (which I don't understand why, and I do need the functionalities defined in GridWorld.State here). Any explanations? Thanks!
UPDATE
Anyway I am seeing my design pattern quite weird, since if State in SimpleGridWorld does not inherit GridWorld.this.State, dynamics would refer to the unimplemented one defined in the root trait World (which makes sense because the implementation in GridWorld may use the functionalities of GridWorld.this.State which may not exist in SimpleGridWorld.this.State). But what I want is:
XXXWorld.this.State must inherit its super.State (or just use it)
dynamics always refers to super.dynamics if implemented in the super trait/class unless overrided here.
How can I do this? I think it is not a totally irrelevant question, and probably the answer to the previous one would tell me how to redesign my pattern.
How about:
trait World {
type State
def dynamics(s: State): State
}
trait GridWorld extends World {
type State = MyState
class MyState {} // concrete
def dynamics(s: State) = s // concrete
}
trait SimpleGridWorld extends GridWorld {
class MyState extends super.MyState {} // concrete
def foo {dynamics(new MyState)} // compiler error; ok
}

Bidirectional Links in Traits with a Single Type

I am trying to create a trait that implements a tree with bidrectional links such that when a node adds a parent, that node is added to the parent's children. The error I get below is:
type mismatch; found :PolyTree.this.type (with underlying type PolyTree[T]) required: T
Any idea why this code is getting an error and what is needed in order to make this code work:
trait PolyTree[T <: PolyTree[T]] {
private val _parents: ListBuffer[T] = ListBuffer()
private val _children: ListBuffer[T] = ListBuffer()
def addParent(parent: T): PolyTree[T] = {
if (parent == this)
throw new IllegalArgumentException();
_parents += parent
parent._children += this // Error
this
}
}
The error occurs because the type of 'parent._children' is 'T', while the type of 'this' is 'PolyTree[T]', which are different types in Scala.
You can fix the error by inserting the the following self-type annotation at the top of the trait:
self: T =>
This is necessary because without it, the following would be valid code:
class TreeOne extends PolyTree[TreeOne]
class TreeTwo extends PolyTree[TreeOne]
TreeTwo is allowed to use TreeOne as the type parameter, because TreeOne satisfies the condition that T <: PolyTree[T]. However, once you add the self-type annotation, Scala essentially tries to cast self/'this' in TreeTwo to 'T' (TreeOne) at compile-time, finds that this isn't type-safe, and rejects the declaration of TreeTwo with the error:
error: illegal inheritance
self-type TreeB does not conform to PolyTree[TreeA]'s selftype TreeA'
I'm not the best at understanding or explaining this stuff, but you can garner a bit more knowledge from Chapter 12. The Scala Type System in O'Reilly's 'Programming Scala'.