How to handle optional in Protocol Buffers (proto3)

Protocol Buffers has had required and ʻoptional` removed in proto3. Regarding the process of deletion in the first place, see @qsona's Entry for an easy-to-understand summary. Thank you.

The problem is that in proto3, each field has a default value, so the field with the default value is from the user side.

  1. A value similar to the intentionally set default value
  2. Default value not set because it does not exist It means that you cannot judge either.

In other words, how to express an optional value.

How to express optional

There are several options, but the answer from Stack Overflow is helpful. Will be.

  1. As a separate field, explicitly express the presence or absence

schema.proto


message User {
  int32 id = 1;
  bool has_name = 2; //Indicates the existence of name
  string name = 3;   //Actual value
}

Example(Java)


User user1 = User.newBuilder()
		.setHasName(true)
		.setName("Tom")
		.build();

User user2 = User.newBuilder()
		.setHasName(false) //The default value is false, so you don't actually need a set
		.build();

user1.getHasName(); // true
user1.getName();    // "Tom"

user2.getHasName(); // false
user2.getName();    // ""
  1. Use oneof

schema.proto


message User {
  int32 id = 1;
  oneof name_optional {
    string name = 2; //Wrap the handling value with one of
  }
}

Example(Java)


User user1 = User.newBuilder()
		.setName("Tom")
		.build();
User user2 = User.newBuilder()
		.build();

user1.getNameOptionalCase(); // User.NameOptionalCase.NAME
user1.getName();             // "Tom"

user2.getNameOptionalCase(); // User.NameOptionalCase.NAMEOPTIONAL_NOT_SET
user2.getName();             // ""
  1. Use google / protobuf / wrappers.proto

schema.proto


message User {
  int32 id = 1;
  google.protobuf.StringValue name = 2;
}

Example(Java)


User user1 = User.newBuilder()
		.setName(StringValue.newBuilder().setValue("Tom").build())
		.build();
User user2 = User.newBuilder()
		.build();

user1.hasName();            // true
user1.getName().getValue(); // "Tom"

user2.hasName();            // false
user2.getName().getValue(); // ""

Consideration

The first thing we all have in common is that no matter which option you choose, you cannot force it to be an optional value. * 1 Therefore, for any option, it is necessary to procedurally perform check for existenceprocess for value.

In 1, the notation is very simple, but the compiler cannot guarantee the relationship between the two fields, and it is necessary to support it with comments.

Compared to 1, 2 has the advantage of being able to express the presence or absence of fields at the compiler level, but it is a little strange usage from one of where multiple fields are assumed.

3 is intuitive and easy to use when dealing with optional values, but it also has some disadvantages.

--Slightly verbose, such as needing a builder for wrappers or calling getValue () to retrieve values --If you want to make a non-primitive value optional, you need to use it together with 1 or 2, and there are two ways to express optional, which cannot be unified.

Example:

schema.proto


message User {
  int32 id = 1;
  Fullname fullname = 2;
}

message Fullname {
  string first_name = 1;
  string last_name = 2;
}

For example, in such a case, wrapper is only provided with the following types, so it cannot be used if you want to make each full name optional.

DoubleValue
FloatValue
Int64Value
UInt64Value
Int32Value
UInt32Value
BoolValue
StringValue
BytesValue

Therefore, if you want to unify optional expressions, it is easy to understand to unify with 1 or 2.

Summary

Protocol Buffers is a schema language with compact specifications, and features low learning costs and good readability. However, for that reason, some expressions that are common to others have been removed, and I think that more expressions can be made by using them while covering them in a timely manner.

Recommended Posts

How to handle optional in Protocol Buffers (proto3)
How to handle TSV files and CSV files in Ruby
How to use java Optional
[Java] How to use Optional ②
How to handle an instance
[Java] How to use Optional ①
How to handle exceptions coolly with Java 8 Stream or Optional
Differences in how to handle strings between Java and Perl
How to use Lombok in Spring
How to find May'n in XPath
How to hide scrollbars in WebView
How to run JUnit in Eclipse
How to iterate infinitely in Ruby
[Rails] How to write in Japanese
How to run Ant in Gradle
How to master programming in 3 months
How to learn JAVA in 7 days
How to get parameters in Spark
How to install Bootstrap in Ruby
How to use InjectorHolder in OpenAM
How to introduce jQuery in Rails 6
How to use classes in Java?
How to name variables in Java
How to set Lombok in Eclipse
How to concatenate strings in java
How to install Swiper in Rails
[swift5] How to specify color in hexadecimal
How to implement search functionality in Rails
How to implement date calculation in Java
How to implement Kalman filter in Java
Multilingual Locale in Java How to use Locale
How to get date data in Ruby
How to use custom helpers in rails
How to reflect seeds.rb in production environment
How to use named volume in docker-compose.yml
How to filter JUnit Test in Gradle
How to insert a video in Rails
[java] Summary of how to handle char
How to standardize header footer in Thymeleaf
How to include Spring Tool in Eclipse 4.6.3?
How to add jar file in ScalaIDE
How to do base conversion in Java
[Swift] How to fix Label in UIPickerView
How to have params in link_to method
How to use MySQL in Rails tutorial
Change List <Optional <T >> to Optional <List <T >> in Java
How to fix system date in JUnit
How to implement coding conventions in Java
How to embed Janus Graph in Java
[rails] How to configure routing in resources
How to map tsrange type in Hibernate
How to get the date in java
How to handle sign-in errors with devise
How to implement ranking functionality in Rails
How to use environment variables in RubyOnRails
How to implement asynchronous processing in Outsystems
How to publish a library in jCenter
How to specify id attribute in JSF
Understand in 5 minutes !! How to use Docker
How to overwrite Firebase data in Swift
How to use credentials.yml.enc introduced in Rails 5.2