scalapb / ScalaPB

Protocol buffer compiler for Scala.

Home Page:https://scalapb.github.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

allow_alias equality semantics differ between generated Scala and Java code

awwsmm opened this issue · comments

allow_alias allows two Protobuf enum variants to share the same value, for example

enum People {

  option allow_alias = true;

  // ...
  GeddyLee = 10;
  NeilPeart = 11;
  TheProfessor = 11; // an alias for NeilPeart
  AlexLifeson = 12;
  // ...
}

Above, NeilPeart and TheProfessor are equivalent with respect to their value, which is 11 in both cases.


ScalaPB generates the following (abridged) Java code for this example

/**
 * <code>TheProfessor = 11;</code>
 */
public static final People TheProfessor = NeilPeart;

The alias is the same object as the original object. Comparing them, we see that they are identically equal

// ScalaTest which passes
it should "be equal in Java" in {
  toJavaValue(proto.People.NeilPeart) shouldEqual toJavaValue(proto.People.TheProfessor)
}

ScalaPB generates the following (abridged) Scala code for this example

@SerialVersionUID(0L)
case object NeilPeart extends People(11) with People.Recognized {
  val index = 11
  val name = "NeilPeart"
  override def isNeilPeart: _root_.scala.Boolean = true
}

@SerialVersionUID(0L)
case object TheProfessor extends People(11) with People.Recognized {
  val index = 12
  val name = "TheProfessor"
  override def isTheProfessor _root_.scala.Boolean = true
}

These two case objects are different objects. For them to equal each other in Scala code, we must override equals / hashCode (comparing them based on value alone). This is currently not being done, and so we have different semantics for generated Scala aliases compared to generated Java aliases.

(THIS IS THE BUG)

The following test fails, though it is equivalent to the Java test above

// ScalaTest which fails
it should "be equal in Scala" in {
  proto.People.NeilPeart shouldEqual proto.People.TheProfessor
}

Thanks for reporting! The java generated code actually creates a reference to the same enum, so following the example above in Scala, would generate:

@SerialVersionUID(0L)
case object NeilPeart extends People(11) with People.Recognized {
  val index = 11
  val name = "NeilPeart"
  override def isNeilPeart: _root_.scala.Boolean = true
  override def isTheProfessor: _root_.scala.Boolean = true  // <-- note this change too
}

@transient val TheProfessor = NeilPeart