google/protobuf.dart

Dart 3 incompatibility: ProtobufEnum instances can't be used in const maps

oprypin opened this issue · 4 comments

If someone makes a const Map of proto enum members, as follows:

const items = {
  SomeProtoEnum.FOO: 'fooo',
  SomeProtoEnum.BAR: 'baar',
};
This happens with any enum, even the simplest one:
enum SomeProtoEnum {
  FOO = 0;
  BAR = 1;
}
class SomeProtoEnum extends $pb.ProtobufEnum {
  static const SomeProtoEnum FOO = SomeProtoEnum._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'FOO');
  static const SomeProtoEnum BAR = SomeProtoEnum._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'BAR');
[...]

In Dart 2.19 that works fine.

But in Dart 3.0 it shows this error:

CONST_MAP_KEY_NOT_PRIMITIVE_EQUALITY
The type of a key in a constant map can't override the '==' operator, or 'hashCode', but the class 'SomeProtoEnum' does.

Indeed, the base class ProtobufEnum has these definitions that clearly cause this:

@override
bool operator ==(Object other);
@override
int get hashCode => value;

They seem to serve no purpose though, as far as I can tell. Maybe they can just be deleted and then compatibility with all versions of Dart will be preserved?

Yeah the instance-based hash-code would probably work fine.

This breakage will affect any file that is at Dart language version 3.0, whether or not the protobuf library or its generated proto definitions switch to language version 3.0.

@kevmoo @devoncarew @scheglov What do you think? Would you agree to delete these definitions soon (and make a release)? It seems totally safe to do and doesn't require waiting. Otherwise real users will start running into this issue soon.

@oprypin – don't have a lot of context, but deleting seems like the right idea.

Although we need to be careful about NON-const hashCode, right?

Theoretically, if these are enum constants, we don't are not supposed more than one instance of them, and so the default hashCode from Object will be enough.

But I don't know for sure how protobuf is supposed to work.
IIRC I have never worked on it.