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

Reflection refactor #625

Merged

Conversation

jskeet
Copy link
Contributor

@jskeet jskeet commented Jul 20, 2015

See comment on first commit for details. I'm not sure that I'm really requesting a pull in its current form, so much as feedback...

@jtattermusch
Copy link
Contributor

After spending a while looking at the changes, I actually don't understand why we need to do the field discovery through ProtobufField attributes.
Also, I don't quite see in what exact use cases is the new reflection API more powerful (that's the reason why we are making things more complex, right?)

@jskeet
Copy link
Contributor Author

jskeet commented Jul 21, 2015

Well, I think in many ways we're actually making things simpler - that was the aim. There's just one entry point for reflection: the descriptor, that you can fetch either via an instance of IMessage, or via the type name.

It's more powerful because given an IMessage, I can get to its MessageDescriptor where I couldn't before - I could get to its FieldAccessorTable, but that was all. (I could go from that to any field to the field descriptor to the containing type, but only if there were some fields... and that's really circuitous anyway.)

We don't have to do field discovery through attributes, but the previous approach of "here are the property names for this type" doesn't work without a FieldAccessorTable per type - there's no obvious place to put them. One option would be to change the Type[] of generated types to something more structured, which would include the properties, nested types and nested enums. Other suggestions welcomed.

@jskeet
Copy link
Contributor Author

jskeet commented Jul 21, 2015

Rebased to csharp-experimental. Will see how the CI builds do...

Thinking more about the field access part, I think I am happy with the accessors being separate types from the rest of the descriptors - they are about interacting with instances of messages instead of just describing the "static" state. It also means we'll be able to represent "no field access available" by returning null from the accessor properties.

Changes in brief:
1. Descriptor is now the entry point for all reflection.
2. IReflectedMessage has gone; there's now a Descriptor property in IMessage, which is explicitly implemented (due to the static property).
3. FieldAccessorTable has gone away
4. IFieldAccessor and OneofFieldAccessor still exist; we *could* put the functionality straight into FieldDescriptor and OneofDescriptor... I'm unsure about that.
5. There's a temporary property MessageDescriptor.FieldAccessorsByFieldNumber to make the test changes small - we probably want this to go away
6. Discovery for delegates is now via attributes applied to properties and the Clear method of a oneof

I'm happy with 1-3.
4 I'm unsure about - feedback welcome.
5 will go away
6 I'm unsure about, both in design and implementation. Should we have a ProtobufMessageAttribute too? Should we find all the relevant attributes in MessageDescriptor and pass them down, to avoid an O(N^2) scenario?

Generated code changes coming in the next commit.
@jtattermusch
Copy link
Contributor

I took another look.

What looks good:
-- the integration of descriptors and field accessors, and providing a way
-- the way Descriptors are exposed (as a static property + explicitly implemented property on IMessage)
-- field accessors being separate types from descriptors

What I don't like:
-- the idea of introducing field attributes that will be visible publicly just to be able to build the descriptor objects internally (along with introducing the N^2 initialization algorithm). We should definitely come up with an alternative approach.

What I haven't seen:
-- what is the expected way user will access the fields in different scenarios. My understanding is I supposed to grab the accessors using Descriptor.FindFieldByName("my_field").Accessor , Descriptor.FindFieldByNumber(25).Accessor or by iterating though Descriptor.Fields. First two feel a bit clumsy and if they are expected to be used often, we might want to consider adding some kind of shortcut ( like Descriptor.FieldAccessors view with [ ] indexer that accepts both int and string maybe).
-- it looks like for Oneofs, you only have the list of OneofDescriptors and you can't easily access a oneof by its name

Nit: please grep for IReflectedMessage occurences, I think I saw some leftovers.

@jskeet
Copy link
Contributor Author

jskeet commented Jul 22, 2015

I've been thinking about the attribute aspect, and I think I've worked out a better alternative. Will try that this morning.

Field access: it's not clear to me how people do typically use reflection, other than when iterating over fields (as we do in JSON, for example.) Your FieldAccessors indexer seems like a good idea though. I suggest we try to get the guts done and merged first, then we can experiment with this a little.

Oneof access by name: I can definitely add that fairly easily.

@jtattermusch
Copy link
Contributor

Good job on finding a workaround for the attributes! Initially, I thought it's going to be easy but I spent quite a while trying to figure it out (and still haven't).

Instead, introduce GeneratedCodeInfo which passes in what we need, and adjust the codegen to take account of this.
@jskeet
Copy link
Contributor Author

jskeet commented Jul 22, 2015

The AppVeyor build failure appears to be for commit 4668c3d - I'm not sure how to prod it to rerun...

@jskeet
Copy link
Contributor Author

jskeet commented Jul 22, 2015

Whoops, no - I've found it. I accidentally made a change in csharp_message which I didn't mean to. Will commit the change and regenerated code in a minute.

@jtattermusch
Copy link
Contributor

LGTM, thanks for taking the time to remove protobuf attributes. The solution looks much better now.

jtattermusch added a commit that referenced this pull request Jul 22, 2015
@jtattermusch jtattermusch merged commit 7b5c396 into protocolbuffers:csharp-experimental Jul 22, 2015
@jskeet jskeet deleted the reflection-refactor branch July 23, 2015 05:50
adellahlou pushed a commit to adellahlou/protobuf that referenced this pull request Apr 20, 2023
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.

None yet

3 participants