Allow numeric types to be optional |
||||||||||
Issue descriptionNumeric types cannot be nullable in Mojo. It would significantly simplify the design of Mojo interfaces and discourage the use of wrapping singular values in a struct to allow optional values.
,
Oct 19 2016
,
Oct 19 2016
We could implement this in the message structure as an implicit bool field in addition to the numeric field, and it'd be simple enough to support for C++ bindings with base::Optional, but it doesn't seem like it would necessarily translate well to all supported languages. It would be kind of surprising if for JS we actually generated a "foo" and "has_foo" field for an "int32? foo" spec, but the alternative would be something worse like having an integer value that might be 0 or null.
,
Oct 19 2016
JavsScript could use undefined? Yes/no?
> obj = { a: 1, b: null, c: undefined }
Object {a: 1, b: null, c: undefined}
> obj.a + 1
2
> obj.b + 1
1
> obj.c + 1
NaN
,
Oct 19 2016
The null issue I was thinking about still applies to undefined:
,
Oct 20 2016
Weird, didn't get posted from email. I was thinking of this:
> if (obj.a) { /* is it zero or null or undefined? */ }
I'm sympathetic to the desire to have optional primitive types though, and we should revisit it. Java can used boxed values, and we could probably find something acceptable for JS, i.e. use an Object wrapper for optional primitives similar to boxing or base::Optional:
{ valid: true, value: 42 }
If we're going to do this, I want to be consistent across all types (i.e. all optional params/fields should be wrapped the same way), and that's a larger change. I'd like yzshen's input on this. One nice property is that it would present an opportunity to remove StructPtrs altogether.
In the meantime, FWIW I don't think wrapping a value in a struct is the preferred workaround. Having a companion bool is simpler and more efficient.
interface Foo {
DoStuff(bool has_x, float x, bool has_y, float y);
};
struct Bar {
int32 thing;
bool has_thing;
};
etc.
,
Oct 21 2016
,
Nov 1 2016
I am not quite sure whether it is worth the effort. The alternative -- explicitly defining an accompany boolean value -- doesn't seem too bad. (That being said, I can see some people may prefer base::Optional<int32_t> to two separate fields.) Another minor thing that I can think up: If we go down this direction, we also need to consider how it affects versioning. At the moment, if you extend a struct, the new interface/handle fields (which are all types that support nullable) have to be nullable. If we make primitive types support nullable, what should we do here? Shall we mandate that new primitive fields have to be nullable (for the sake of consistency) or shall we allow them to be non-nullable (for the sake of performance)? > One nice property is that it would present an opportunity to remove StructPtrs altogether. I feel that removing StructPtr is an independent issue. We have done similar things for array and map. We could take on that task even if we don't try to support nullable primitives. WDYT?
,
Jan 9 2017
Mark it as won't fix according to the discussions so far.
,
Jun 9 2017
I'd like to revisit this. While it's possible to wrap fields in structs to simulate this, it's a bit clunky. It provides nice syntactic sugar: otherwise, we end up with code like https://chromium-review.googlesource.com/c/527487/3/extensions/browser/api/usb/usb_api.cc and https://chromium-review.googlesource.com/c/527487/3/chrome/browser/chromeos/printing/usb_printer_util.cc which has to make sure the fields stay in sync manually. It also makes numerical fields more consistent with other types of fields. That being said, I'm not sure how to resolve the versioning issue...
,
Jun 12 2017
Another thing worth considering is how the layout should look like. (Not saying that this is something unsolvable; just exploring the idea.) Today if we have a
struct Foo {
bool has_field1;
int32 field1;
bool has_field2;
int32 field2;
};
The booleans will be packed into the same byte. Imagine we introduce optional primitive types "int32?", do we pack int32 and boolean like they are separate fields, or do we group them together? What if we have array<int32?>?
I can see that it is a convenient feature. However, it seems to introduce complexity and inconsistency (such as the versioning issue) which outweighs the gain. Unless there is a design proposal that addresses these issues, I lean towards not introducing this feature.
,
Jun 13 2018
This issue has been Available for over a year. If it's no longer important or seems unlikely to be fixed, please consider closing it out. If it is important, please re-triage the issue. Sorry for the inconvenience if the bug really should have been left as Available. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Aug 7
For what it's worth, I just came across this while trying to send "optional" data over mojo. I'd like it if there were a way to just make numeric types nullable, but IIUC, the suggested workaround is an accompanying bool per value?
,
Oct 17
,
Oct 18
Another place this showed up is https://chromium-review.googlesource.com/c/chromium/src/+/1282026: since enums aren't optional, a new enum field needs to be wrapped in a struct just for ARC++ backwards compatibility...
,
Oct 18
I may be misunderstanding, but optional is not the same as being able to support versioning. You can add a MinVersion'd enum field to a struct.
,
Oct 18
The mojo docs for versioning say that "Newly added fields of Mojo object or handle types MUST be nullable". https://chromium.googlesource.com/chromium/src/+/master/mojo/public/tools/bindings/README.md#Versioning Enums are not nullable though so would adding a MinVersion'd enum break message validation?
,
Oct 18
"Mojo object or handle" types does not include POD types. We should probably clarify the docs.
,
Oct 18
The spirit of the constraint is that a newer version of the bindings must be able to fill in reasonable default values when receiving a structure from an older version. Neither Mojo objects (like other structs, interface handles, and interface requests) nor Mojo handles have any reasonable default value other than null, so the field must be marked nullable. POD types can just be zeroed.
,
Nov 15
Triaging this as something to be investigated more closely.
The simple approach here would be to use offset indirection (rather than encoded bools) for optional numeric fields. I think that is too much overhead to be justified.
It would mean an int32? costs 16 bytes instead of 4-8 bytes. Two int32s back-to-back can normally be packed into 8 bytes, but if they're both optional they will now always consume a total of 32 bytes. It gets way worse with bools. Consider that 4 bools are normally packed into a single byte, but 4 nullable bool?s would consume a total of *64 bytes*.
I think we could get away with making:
struct A {
int32? x;
};
syntactic sugar for
struct A {
bool has_x;
int32 x;
};
(This is just in terms of underlying encoding, not the bindings we expose, which would just be e.g. base::Optional<int32_t>)
Versioning doesn't actually seem like much of an issue to me. I think of course we require newly added numeric fields to be nullable in versioned structures. There isn't really much performance overhead.
|
||||||||||
►
Sign in to add a comment |
||||||||||
Comment 1 by mbrunson@chromium.org
, Oct 19 2016