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 changes #320

Closed
skippy opened this issue Apr 29, 2015 · 6 comments
Closed

ruby changes #320

skippy opened this issue Apr 29, 2015 · 6 comments

Comments

@skippy
Copy link
Contributor

skippy commented Apr 29, 2015

hello,

would you be open to the following changes:

  • allow repeated fields to accept a new array object? Ie, to allow something likemessage.repeated_field = [1,2,3] Currently, this throws a TypeError: Expected repeated field array
  • allow repeated fields to accept an empty array object? I.E., to allow something like message.repeated_field += []. Currently, this throws a TypeError: Repeated field array has wrong message/enum class
  • to make repeated fields act more like a ruby array, such as responding to #size

My caveat is that it has been 10+ yrs since I've done any C. these should be straight forward changes, but I may need a bit more of a review than normal :) With that said, if these changes are acceptable, I'll submit a PR

@cfallin
Copy link
Contributor

cfallin commented Apr 29, 2015

Hi @skippy,

responding to #size

Yes, we'd love a PR for that! They respond to #length but we're happy to flesh out the API with convenience methods/aliases where appropriate.

message.repeated_field += []

The append (+=) operator works fine for me:

x = Google::Protobuf::RepeatedField.new(:int32)
x += []
x += [1,2,3]

Did you mean to assign it (= rather than +=) instead? There's the #clear method for that :-)

allow repeated fields to accept a new array object?

This question was actually extensively discussed/debated internally when we designed the API, and in the end we disallowed it (and added #replace(list) instead; see end below).

The reason is the result of combining (i) the typechecking of list elements and (ii) principle of least surprise when the user holds aliases / multiple references to a list field.

Consider what options we have if the user assigns a list my_list to message.repeated_int32. We can either (1) immediately convert the raw Ruby array to an instance of our class that checks for integers on #push, #[]= (element update), etc., or we (2) keep the raw Ruby array as the canonical data structure.

If we do (2), then we've broken the typechecking that we do everywhere else. The user could assign an empty Ruby array [] to a repeated int32 field then subsequently push strings onto it. If all of the Ruby module were typechecking-free (or typecheck-only-at-serialize-time), this might be OK, but as it is, we decided everywhere else to typecheck eagerly (at message mutation time), so (2) is inconsistent.

If we do (1), then message.repeated_int32 subsequently returns a reference to a new object! What if the user did the following?

my_list = [1, 2, 3]
msg.repeated_int32 = my_list
my_list.push(4)
msg.repeated_int32  # => [1, 2, 3]   <--- missing the last element because we dropped the aliasing!

So we can't do (1) either.

Given that we can't do (1) or (2), and these are logically the only choices (in the "A or not A" sense) if we allow assignment of raw Ruby arrays to repeated fields, we concluded that we can't allow assignment of raw arrays to repeated fields.

We nevertheless tried to make things a little more convenient where possible, which is why there is the #clear method and the += append method that takes a raw list.

There is also a #replace method that takes a raw list and replaces the existing content with the given Ruby list. We distinguish this case from the above reasoning because it's clear that a copy occurs / no substructure sharing is going on, so it's OK, whereas a raw object assign that implies a copy is not.

@skippy
Copy link
Contributor Author

skippy commented May 1, 2015

Hi @cfallin,

thank you for the thoughtful response!

I understand about wanting to do typing at time of setting rather than at time of encode/decode. But I think having Google::Protobuf::RepeatedField act like a ruby array can help a lot with duck typing. Little things add up: missing #first and #last; no #join; if you access a location that doesn't exist, an exception is returned instead of a nil; once an object is set you cannot remove it, etc.

In other Protobuf libs, the repeated field is a wrapper/delegator around an array object. I think the same pattern could be applied here with success. The other approach is to write the syntactic sugar in regular ruby and not fix it in the c/java guts. This may be a tad more inefficient, but it could really help smooth out the duck typing.

@cfallin, why don't I start sending in PRs with tests (see if I can get to it this weekend), and accept/deny/discuss as you and the team see fit. No harm if they are rejected :) I like this library quite a bit and I can always monkey patch in the syntactic sugar, myself, as needed.

a few questions on submissions:

  • I'll sign the CLA of course
  • do you want to keep things exclusively in C/java, or can I start submitting some patches in Ruby space?

@cfallin
Copy link
Contributor

cfallin commented May 1, 2015

Hi @skippy,

Yes, I think fleshing out the RepeatedField API to match as many methods on Array as is reasonable is the right thing to do. We had implemented sort of a bare minimum to look like an array but we're happy to add more! Adding patches in the Ruby wrapper module is fine for things like this.

I saw your PRs -- I'll go review those now. Thanks!

@skippy
Copy link
Contributor Author

skippy commented May 1, 2015

@cfallin thanks!

This was referenced May 1, 2015
@cfallin
Copy link
Contributor

cfallin commented May 1, 2015

I'll go ahead and close this issue since I think your PRs addressed your immediate concerns (?) but please do feel free to send more PRs if you have any other issues/improvements for the RepeatedField API.

@cfallin cfallin closed this as completed May 1, 2015
@skippy
Copy link
Contributor Author

skippy commented May 1, 2015

more on their way :) but leaving this closed sounds good

bithium pushed a commit to bithium/protobuf that referenced this issue Sep 4, 2023
…hmark

Added a benchmark for ctype=STRING_PIECE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants