Skip to content
This repository was archived by the owner on Sep 26, 2023. It is now read-only.

Conversation

@andreamlin
Copy link
Contributor

@andreamlin andreamlin commented Feb 22, 2019

So that EmptyMessage has the same calling structures as other ApiMessage implementations, e.g. the Address resource class.

@googlebot googlebot added the cla: yes This human has signed the Contributor License Agreement. label Feb 22, 2019
@codecov
Copy link

codecov bot commented Feb 22, 2019

Codecov Report

Merging #685 into master will decrease coverage by 0.22%.
The diff coverage is 0%.

Impacted file tree graph

@@             Coverage Diff             @@
##             master    #685      +/-   ##
===========================================
- Coverage     75.63%   75.4%   -0.23%     
  Complexity     1029    1029              
===========================================
  Files           195     195              
  Lines          4613    4627      +14     
  Branches        356     356              
===========================================
  Hits           3489    3489              
- Misses          966     980      +14     
  Partials        158     158
Impacted Files Coverage Δ Complexity Δ
...java/com/google/api/gax/httpjson/EmptyMessage.java 0% <0%> (ø) 0 <0> (ø) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 007caf3...709cbfd. Read the comment docs.

@andreamlin andreamlin requested a review from yihanzhen February 22, 2019 18:56
@andreamlin
Copy link
Contributor Author

PTAL

}

public Builder clone() {
Builder newBuilder = new Builder();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could just do return new Builder();?
OTOH, is the method really needed though? cloning a Builder object doesn't sound like a valid use case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because com.google.protobuf.Empty is also a GeneratedMessageV3, I'm pretty sure it would also look like this. (idk how to look at generated protobuf classes tho so i can't confirm)

Copy link
Contributor

@vam-google vam-google Feb 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IntelliJ usually downloads the sources of the maven artifacts used in project automatically, so you can navigate to the sources just from there. If it can't find sources it will show decompiled version (can be good enough as well). The sources of maven artifacts are usually published together with compiled classes (sometimes in same jar, sometimes as a separate -sources.jar). For the Empty class, its sources can be found here: protobuf-java-3.6.1-sources.jar

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this method should be there, let's just keep the method and change it to return new Builder(); then :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

public Builder(EmptyMessage other) {}

public EmptyMessage build() {
return new EmptyMessage();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems you want to enforce singleton on EmptyMessage, then probably:

  • make the constructor private
  • change new EmptyMessage() to DEFAULT_INSTANCE, since we want to make sure there is only one instance of this class
  • probably make a DEFAULT_INSTANCE for Builder. If there will be only one instance of EmptyMessage, then we probably only need one instance of Builder.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted this to emulate the com.google.protobuf.Empty java class.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not that EmptyMessage should be a singleton, only the DEFAULT_INSTANCE.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's OK to make EmptyMessage a singleton, because EmptyMessage does not have any fields, and thus all the instances of this class would be the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@yihanzhen
Copy link
Contributor

I don't fully understand the motivation here, but if you need to make it compatible with other ApiMessage implementations, emulating the surface should be enough. It's a bit unnecessary to emulate the exact implementation of a generated class IMO.

@andreamlin
Copy link
Contributor Author

PTAL

@andreamlin
Copy link
Contributor Author

I figure emulating the implementation of the generated class is the safest thing to do, since the protobuf generated message types have gone through a lot of design review. I myself don't know the subtleties of static variable initialization vs initialization in a static block; I'm not sure how synchronization works with singletons, etc. In any case, this would not be an incorrect implementation.

@yihanzhen
Copy link
Contributor

Oh I see. I also don't have enough knowledge to argue against this. I'm summoning @vam-google to TAL.

@vam-google
Copy link
Contributor

@hzyi-google @andreamlin

As a summoned creature in this PR, I think the most helpful thing I can do here is to provide my view on the PRs motivation and chosen implementation strategy.

About using protobuf implementation as a reference.
The implementation of protobuf's generated classes has definitely gone through tons of reviews and has proven itself to be correct and reliable on practice.

At the same time there are always multiple ways of achieving same result, so the protobuf's way is not the only correct way.

We should keep in mind that protobuf classes are generated. Manually written code and generated code have fundamental differences, because generated code is usually machine/automation friendly and manually written code is human/readability friendly, but the both "codes" (automation-friendly and readability-friendly) may be equally correct. What is good for machine-friendliness is usually bad (not always, but often) for readability and vice versa.

Here by machine/automation friendliness I mean that for generated classes (their implementation, not the surface) the actual "code" of them is not what is generated, but the templates (or whatever is used), from which it is generated. Generated code for code generators (like protoc or gapic-generator) is like what java bytecode is for java compiler, and templates for the code generators are like what java sources are for java compiler. Why does all this matter? Please see the next paragraph.

After the code is created (manually or generated) it must be maintained/modified/improved. For manual case it is all about the code itself, but for the generated case, what should have be maintained is not the generated implementation, but the generator and templates. Using the analogy with java compiler (see above), trying to put generated code in manually written class is like trying to write java directly in bytecode. Yes, I'm absolutely over-exaggerating it here, but there is a portion truth in this exaggeration.

Instead of conclusion: there is nothing wrong in copying some parts of protobuf's generated classes, but I don't think we should make manually written classes look identical to them, because it is going to add a lot of overhead without real benefits.

We may have to make manual clients identical to protobuf ones (including implementation, not only the surface) in case if they have to be used interchangeably (for example if we need to marshal/unmarshal them by protobuf runtime). Is it the case here? Probably no.

Is emulating the surface enough?
Usually (~99% cases) the answer is "Yes". In case if the object has to be serialized/deserialized (marshaled/unmarshaled) or if reflection is used the answer is "It depends". It may be relevant for our case, because our objects are usually sent over the wire. But even in this case it does not mean that implementations have to be identical, they just have to be compatible in case of the concrete scenario of usage.

Static variable initialization vs initialization in a static block
The simple answer is: it should not matter. You may think about inline static variable initialization like about an implicit static block. In other words:

private final static String stuff0 = "oops";

is effectively same as

private final static String stuff0;
static {
    stuff0 = "oops"
}

Both initializations will happen only once, when the class is first initialized (loded into memory from .class files). But keep in mind that in case of static initializers, the order matters.
For example, for the following code

  private static String stuff0 = "oops0";
  static {
    stuff0 = "oops1";
  }

the value of stuff0 is going to be "oops1"

But for the following:

  static {
    stuff0 = "oops1";
  }  
  private static String stuff0 = "oops0";

the value of stuff0 is going to be "oops0".

But if the variable is assigned only once (and is final) it all does not matter, and static block and static inline initialization should be equal to each other.

Synchronization and singletons
I'm not sure what what is the source of confusion here, but in general it is a good attitude to multithreading: we should be afraid of it (because it is almost never possible to make it 100% right). But in those cases when we have to do it, there are two main sources of problems here:

  1. Visibility issues (one thread does not see modifications done in another thread)
  2. Concurrent access issues (two+ threads modify same stuff simultaneously or one thread modifies stuff when another one tries to read it before modification is finished).

The singleton isntance is declared as static final field. Static final fields are always visible to all threads correctly (because they are initialized only once). But this applies only to the reference to the singleton object, that object can have all sorts of nested arbitrarily complicated mutable fields. But it is a general problem, not specific to singletons and/or static initialization blocks. From the point of view of synchronization, using static initialization block or using inline initialization are equally good.

Misc
If some class is doing something weird, and you do not fully understand the details it is usually better to invest time into figuring it out (Stackoverflow is our best friend here, plus some toy programs to check the behavior), and only then making the decision if we want to copy it or no. It is always worth it and pays back (also, there are actually not that many "weird" things in Java, so with time you would have to do it (invest the time into investigation) less and less often, almost never...)

andreamlin added a commit to googleapis/gapic-generator that referenced this pull request Feb 27, 2019
This goes along with [googleapis/gax-java#685](googleapis/gax-java#685), which allows EmptyMessage to be constructed like a proto message.

This allows EmptyMessage to have a non-null test value, just like com.google.protobuf.Empty is constructed.
@codecov-io
Copy link

Codecov Report

Merging #685 into master will decrease coverage by 0.22%.
The diff coverage is 0%.

Impacted file tree graph

@@             Coverage Diff             @@
##             master    #685      +/-   ##
===========================================
- Coverage     75.63%   75.4%   -0.23%     
  Complexity     1029    1029              
===========================================
  Files           195     195              
  Lines          4613    4627      +14     
  Branches        356     356              
===========================================
  Hits           3489    3489              
- Misses          966     980      +14     
  Partials        158     158
Impacted Files Coverage Δ Complexity Δ
...java/com/google/api/gax/httpjson/EmptyMessage.java 0% <0%> (ø) 0 <0> (ø) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 007caf3...42d0c1d. Read the comment docs.

@codecov-io
Copy link

codecov-io commented Feb 28, 2019

Codecov Report

Merging #685 into master will decrease coverage by 0.3%.
The diff coverage is 0%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master     #685      +/-   ##
============================================
- Coverage     75.63%   75.32%   -0.31%     
- Complexity     1029     1030       +1     
============================================
  Files           195      195              
  Lines          4613     4628      +15     
  Branches        356      357       +1     
============================================
- Hits           3489     3486       -3     
- Misses          966      984      +18     
  Partials        158      158
Impacted Files Coverage Δ Complexity Δ
...java/com/google/api/gax/httpjson/EmptyMessage.java 0% <0%> (ø) 0 <0> (ø) ⬇️
...ogle/api/gax/httpjson/HttpJsonCallableFactory.java 24.24% <0%> (-7.76%) 3% <0%> (ø)
...a/com/google/api/gax/tracing/OpencensusTracer.java 87.5% <0%> (+0.29%) 32% <0%> (+1%) ⬆️
...api/gax/tracing/TracedServerStreamingCallable.java 100% <0%> (+8.69%) 2% <0%> (ø) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 007caf3...42d0c1d. Read the comment docs.

@andreamlin
Copy link
Contributor Author

PTAL

@andreamlin
Copy link
Contributor Author

Thanks @hzyi-google and @vam-google !

@andreamlin andreamlin merged commit 1f25467 into googleapis:master Feb 28, 2019
@andreamlin andreamlin deleted the emptymessage_equals branch February 28, 2019 21:03
andreamlin added a commit to googleapis/gapic-generator that referenced this pull request Mar 1, 2019
This goes along with [googleapis/gax-java#685](googleapis/gax-java#685), which allows EmptyMessage to be constructed like a proto message.

This allows EmptyMessage to have a non-null test value, just like com.google.protobuf.Empty is constructed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

cla: yes This human has signed the Contributor License Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants