2

I ran into this behavior which surprised me. Essentially, if I create "the same" XML Elem from two different XML literals, they fail to equal one another. The unique thing here is that I am using a Boolean in one and a String in the other.

scala> import scala.xml._
import scala.xml._

scala> val t: Boolean = true
t: Boolean = true

scala> val fromBoolean: Elem = <b>{t}</b>
fromBoolean: scala.xml.Elem = <b>true</b>

scala> val fromString = <b>true</b>
fromString: scala.xml.Elem = <b>true</b>

scala> fromString == fromBoolean
res0: Boolean = false

Is this the expected behavior?

It seems that Scala is storing the underlying type and a Boolean doesn't strictly equal a String.

Is this correct interpretation, and can anyone explain what exactly is going on here? I couldn't find a way to inspect the underlying type within the two nodes. If I look at the children they just appear to be Nodes.

scala> fromString.child(0)
res1: scala.xml.Node = true

scala> fromBoolean.child(0)
res2: scala.xml.Node = true
dwikle
  • 6,820
  • 1
  • 28
  • 38

1 Answers1

3

Your interpretation is correct. The child of fromString is scala.xml.Text, which extends scala.xml.Atom[String]:

scala> fromString.child(0).getClass.getName
res1: String = scala.xml.Text

scala> fromString.child(0).asInstanceOf[xml.Atom[_]].data.getClass.getName
res2: String = java.lang.String

And the child of fromBoolean is scala.xml.Atom[Boolean]:

scala> fromBoolean.child(0).getClass.getName
res3: String = scala.xml.Atom

scala> fromBoolean.child(0).asInstanceOf[xml.Atom[_]].data.getClass.getName
res4: String = java.lang.Boolean

So the data of fromString's child Atom has type String, and the data of fromBoolean's Atom has type Boolean. The equality implementation of Atom (scala.xml.Atom#strict_==) just compares the data directly, and so the String and the Boolean compare unequal.

I'm not sure what's the purpose of distinguishing the types of Atom data. It seems to me that Atom should compare toString values of its data anyway. So this behaviour might be a bug.

As a workaround, I can advise to convert the atom values to String explicitly. The equality works in that case:

scala> <b>{true.toString}</b> == <b>true</b>
res5: Boolean = true

Scala xml comparison does have more quirks though:

scala> <foo:b xmlns:foo="foo"/> == <foo:b xmlns:foo="bar"/> 
res6: Boolean = true

scala> <b>{"<"}</b> == <b>&lt;</b>
res7: Boolean = false

scala> <b>></b> == <b>&gt;</b>
res8: Boolean = false

So it may be worth it to try implementing comparison manually.

Kolmar
  • 14,086
  • 1
  • 22
  • 25