Skip to content

Make AbstractMessage public in Ruby #12550

@jez

Description

@jez

What language does this apply to?

If it's a proto syntax change, is it for proto2 or proto3?
If it's about generated code change, what programming language?

Ruby

Describe the problem you are trying to solve.

In this change the AbstractMessage parent class was added for Ruby code. The motivation was to be a pure performance win, exploiting how classes and objects are laid out in the Ruby code.

But as it happens, having a common base class that has all these methods defined is particularly convenient. When using an optional static type checker in a Ruby project, it's very easy if you can write Google::Protobuf::AbstractMessage in a type signature, and know that it has all these methods. For example, using Sorbet, it would be possible to write a signature like

sig do
  params(
    proto_class: T.class_of(Google::Protobuf::AbstractMessage),
    bytes: String
  )
  .returns(Google::Protobuf::AbstractMessage)
end
def decode_and_log(proto_class, bytes)
  puts("Decoding with class: #{proto_class.descriptor.name}")
  proto_class.decode(bytes)
end

Right now it's annoying to write signatures for these methods, because methods like descriptor and decode aren't actually defined on the only other common type in the inheritance hierarchy, MessageExts::ClassMethods:

[dev] main:0> Google::Protobuf::MessageExts::ClassMethods.instance_methods
=> []

So there's not a convenient type you can write—but there would be if AbstractMessage were not a private constant.

Describe the solution you'd like

Can we remove private_constant :AbstractMessage?

private_constant :AbstractMessage

Describe alternatives you've considered

An alternative would be to actually define the methods on MessageExts::ClassMethods.

In the Sorbet type system this is slightly less ergonomic to use, MessageExts and MessageExts::ClassMethods look like completely orthogonal modules to the type system. (For example, it doesn't know that MessageExts::ClassMethods has all the methods that a normal class would have, like .name or .ancestors.) That means you have to go around writing things like T.all(Google::Protobuf::MessageExts, Class) which is confusing.

It's a lot easier to just mention the exact superclass you want in your type annotation, which in this case is AbstractMessage.

Additional context
Add any other context or screenshots about the feature request here.

Metadata

Metadata

Assignees

Labels

discussioninactiveDenotes the issue/PR has not seen activity in the last 90 days.ruby

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions