Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ruby: Use class inheritance to save memory #10281

Merged

Conversation

casperisfine
Copy link
Contributor

The only difference between all the Message classes is just their descriptor instance variable.

So rather than create an entirely new class from scratch every time we can simply inherit from an abstract class.

This shink each Message class from 1456 bytes to 944 bytes, and the singleton class of each from 960 to 792, for a total of 680 bytes saved per message class, so a ~28% reduction.

@haberman
Copy link
Member

haberman commented Aug 9, 2022

I wish there was a way to do this that didn't affect the public API.

If we do this, developers can start writing:

if obj.kind_of? Google::Protobuf::AbstractMessage
  # This is a protobuf
end

That might not be the worst thing, but it would commit us to maintaining this inheritance hierarchy.

@casperisfine
Copy link
Contributor Author

I can make that constant private.

The only difference between all the `Message` classes is just
their `descriptor` instance variable.

So rather than create an entirely new class from scratch every time
we can simply inherit from an abstract class.

This shink each `Message` class from `1456` bytes to `944` bytes, and
the singleton class of each from `960` to `792`, for a total of
`680` bytes saved per message class, so a ~28% reduction.
@casperisfine casperisfine force-pushed the ruby-smaller-message-classes branch from 6c5cacb to 7309e88 Compare August 10, 2022 08:38
@casperisfine
Copy link
Contributor Author

Done:

>> require 'google/protobuf'
=> true
>> Google::Protobuf::AbstractMessage
(irb):2:in `<main>': private constant Google::Protobuf::AbstractMessage referenced (NameError)

@deannagarcia deannagarcia merged commit 68816b9 into protocolbuffers:main Aug 12, 2022
jez added a commit to jez/protoc-gen-rbi that referenced this pull request Apr 26, 2023
In our codebase we're fighting a constant battle against the codebase's
growing size. Having a larger codebase makes basically everything
slower, from creating an initial dev environment to type checking code
to creating deploy artifacts.

Generated protobuf files end up contributing a lot to the bloat of our
codebase. These two options make protoc-gen-rbi generate less code. The
options:

- `hide_common_methods`

  This option hides the common methods like `decode_json` and `to_h`
  that protoc-gen-rbi would otherwise create. While it's most accurate
  to have those methods be defined on these classes, it's actually
  possible to get basically the same type safety by defining these
  methods elsewhere, using `T.attached_class`.

- `use_abstract_message`

  A recent `google-protobuf` PR changed the superclass of all message
  classes:

  <protocolbuffers/protobuf#10281>

  The new superclass, `Google::Protobuf::AbstractMessage`, is
  technically private. However, having a common superclass is quite
  convenient for a number of reasons, and codebases may wish forcibly
  make this class publicly visible. If that's been done, it's nice to be
  able to mention that superclass instead of the `include` and `extend`
  calls, because `AbstractMessage` is exactly defined by just an empty
  class with those two mixins, and getting rid of those calls generates
  less code.

  For more discussions on the merits of making this class public:

  <protocolbuffers/protobuf#12550>

I'm happy to split this change apart if you think it would be better
that way.

On Stripe's codebase, these changes amount to a 4% reduction in Sorbet's
peak memory usage, and a 1% improvement to time spent type checking, so
I'm quite eager to get this change or some equivalent version of it
landed.
jez added a commit to jez/protoc-gen-rbi that referenced this pull request Apr 26, 2023
In our codebase we're fighting a constant battle against the codebase's
growing size. Having a larger codebase makes basically everything
slower, from creating an initial dev environment to type checking code
to creating deploy artifacts.

Generated protobuf files end up contributing a lot to the bloat of our
codebase. These two options make protoc-gen-rbi generate less code. The
options:

- `hide_common_methods`

  This option hides the common methods like `decode_json` and `to_h`
  that protoc-gen-rbi would otherwise create. While it's most accurate
  to have those methods be defined on these classes, it's actually
  possible to get basically the same type safety by defining these
  methods elsewhere, using `T.attached_class`.

- `use_abstract_message`

  A recent `google-protobuf` PR changed the superclass of all message
  classes:

  <protocolbuffers/protobuf#10281>

  The new superclass, `Google::Protobuf::AbstractMessage`, is
  technically private. However, having a common superclass is quite
  convenient for a number of reasons, and codebases may wish forcibly
  make this class publicly visible. If that's been done, it's nice to be
  able to mention that superclass instead of the `include` and `extend`
  calls, because `AbstractMessage` is exactly defined by just an empty
  class with those two mixins, and getting rid of those calls generates
  less code.

  For more discussions on the merits of making this class public:

  <protocolbuffers/protobuf#12550>

I'm happy to split this change apart if you think it would be better
that way.

On Stripe's codebase, these changes amount to a 4% reduction in Sorbet's
peak memory usage, and a 1% improvement to time spent type checking, so
I'm quite eager to get this change or some equivalent version of it
landed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants