The best suggestion I've seen for this in proto3 is to wrap your field in a singleton oneof. This will allow you to check for presence / absence again, similar to proto2.
message blah
{
oneof foo_ { sint32 foo = 1; }
}
In Python generated code this is extremely smooth as foo
can be directly operated on as a scalar as if it wasn't inside a oneof.
Unfortunately, for Java I think support for oneof's is far uglier. Google also purposely removed the hasFoo() generated class function in proto3. So you would need to consult the getFooCase() of the oneof instead to check for presence or absence.
https://developers.google.com/protocol-buffers/docs/reference/java-generated#oneof-fields
Yes, I realize this means tons of oneof's and any attendant hassle they bring. On the plus side, there is no overhead on the wire.
The second best suggestion I've seen is to use a submessage to wrap your scalar because presence / absence of submessages is still supported. There are the Well Known Types (WKT) in google.protobuf.wrappers.proto. If you use those, then you may even get extra special treatment in your preferred language where the wrapped scalar can be easily operated on as if the containing submessage didn't exist (or so I've read, not entirely sure on this point myself).