Reputation: 67838
Say we have these nested classes and an instantiation of A
:
class A {
case object B
case class C(c: Int)
}
val a1 = new A()
Now I can check that a1.B
is an instance of a1.B.type
but how can I check that the type of a1.B
is an instance of any A#B.type
because the compiler won’t accept that syntax.
a1.B.isInstanceOf[a1.B.type]
res: Boolean = true
a1.B.isInstanceOf[A#B.type]
<console>:1: error: ']' expected but '.' found.
a1.B.isInstanceOf[A#B.type]
^
For the case class it seems to work without problems:
a1.C(0).isInstanceOf[a1.C]
res: Boolean = true
a1.C(0).isInstanceOf[A#C]
res: Boolean = true
Follow-up question: When I have
val a1 = new A()
val a2 = new A()
is there a function that does an equality check without taking path-dependency into account? Eg. it should return true
when comparing a1.B
and a2.B
. For example:
a1.B =#= a2.B
true
a1.C(0) =#= a2.C(0)
true
a1.C(0) =#= a2.C(1)
false
Edit: For clarification: Just introducing a common trait for B
is not enough as I want to bet able to distinguish between case objects:
class A {
trait BB
case object B1 extends BB
case object B2 extends BB
}
val a1 = new A
val a2 = new A
a1.B1 =#= a2.B1 // should be true
a1.B2 =#= a2.B2 // should be true
a1.B1 =#= a1.B2 // should be false
a1.B1 =#= a2.B2 // should be false
Now, the .hashCode
(or .##
) method seems to solve the problem:
a1.B1.## == a2.B1.## // true
a1.B1.## == a2.B2.## // false
but maybe there is a more elegant solution (I’d also like to be able to use a1.B1
in a pattern match for example).
Upvotes: 2
Views: 108
Reputation: 5977
Just use full form for expressing existential types.
Here your example:
class A {
case object B1
case object B2
case class C(c: Int)
}
val a1 = new A()
I've added another case object to demonstrate that they could be distinguished and so I have not write an obscure equivalent for AnyRef
type AB1 = a.B1.type forSome {val a : A}
type AB2 = a.B2.type forSome {val a : A}
scala> a1.B1.isInstanceOf[AB1]
res0: Boolean = true
scala> a1.B1.isInstanceOf[AB2]
res1: Boolean = false
I've introduced type aliases AB1
and AB2
for convenience. But that types may be inlined into isInstanceOf
if there is a need.
Upvotes: 4
Reputation: 67838
I am not sure if this is purely a syntax thing but the following seems to solve it:
class A {
case object B
type BType = B.type
case class C(c: Int)
}
val a1 = new A()
val a2 = new A()
a1.B.isInstanceOf[a1.B.type]
res: Boolean = true
a1.B.isInstanceOf[A#BType]
res: Boolean = true
And then I can kill the (2.11) compiler with
a1.B match {
case _: A#BType => println("ABC")
}
> error: scala.MatchError: (?_1.type#B.type,a1.B.type) (of class scala.Tuple2)
In dotty it works though and interestingly enough a1.B.type
and a1.BType
are different:
List(a1, a2) foreach { a =>
a.B match {
case _: a1.B.type => println("Matches a1")
case _: a2.B.type => println("Matches a2")
case _: A#BType => println("Matches a1 and a2")
case _: a1.BType => println("Matches a1 and a2")
case _: a2.BType => println("Matches a1 and a2")
case x => println(x)
}
}
Upvotes: 0
Reputation: 3400
I think a1.B.isInstanceOf[A#B.type]
is syntacticly wrong. There is no .type
How about using a inner trait
class A{
trait BTrait
object B extends BTrait
}
val a1 = new A
a1.B.isInstanceOf[A#BTrait] // this is true
if you want your inner instances to be equal independent of the outer instance,
a1.C(0) == a2.C(0)
is ture if you declare C
as
final case class C()
this does not work for object
s
Upvotes: 1