Field | Value |
---|---|
Status | Accepted |
Authors | porce@google.com |
Submitted | 2018-07-17 |
Reviewed | 2018-09-27 |
A FIDL struct member may have a default value. Today, support of defaults is partially implemented (see section below), this proposal aims to clarify how defaults ought to behave.
Non-motivation includes:
It is not a motivation to save bytes in wire format or to save processing power in doing encoding or decoding.
Defaults can be expressed in the FIDL language on struct members:
fidlc
of assignability of a literal to a struct member. It is possible to have a string literal “hello” assigned to a bool, a negative number assigned to a uint, or an out-of-bound number assigned to an int16.For example (from //zircon/tools/fidl/examples/types.test.fidl):
struct default_values { bool b1 = true; bool b2 = false; int8 i8 = -23; int16 i16 = 34; int32 i32 = -34595; int64 i64 = 3948038; uint8 u8 = 0; uint16 u16 = 348; uint32 u32 = 9038; uint64 u64 = 19835; float32 f32 = 1.30; float64 f64 = 0.0000054; string s = "hello"; };
Default values MAY be defined on struct members. Defaults appear at the end of a field definition with a C-like = {value}
pattern.
// cat.fidl enum CatAction : int8 { SIT = -10; WALK = 0; SNEAK = 2; }; struct Location { uint8 pos_x = 10; // Position X uint8 pos_y; // Position Y. Default unspecified. Fall-back to 0 float32 pos_z = 3.14; // Position Z. float32 pos_t; // Default unspecified. Fall-back to 0.0 }; struct Cat { string name; // Automatic default to empty string CatAction action = CatAction::SNEAK; Location loc; };
Please refer to FTP-006 which clarified the semantics of defaults, and requirements on bindings.
bool
, int8
, int16
, int32
, int64
, uint8
, uint16
, uint32
, uint64
, float32
, float64
string
, string:N
string:N
shall zero out the memory that is reserved, and not used.array<T>:N
vector<T>
, vector<T>:N
string?
, string:N?
, vector<T>?
, vector<T>:N?
handle
struct
struct
may have a default, a struct
itself does not have a default.union
union
, or that of a substructure (in any depth) of the union
shall be ignored.The focus is on the value itself, and not on the manner of assigning the value. This implies two things at least:
Here are some example implemention ideas for C, Rust, and Go Bindings
// in FIDL "default.fidl" struct Location { uint8 pos_x = 10; uint8 pos_y = 20; uint8 pos_x; // Should be set to "zero" according to above. };
// C binding "defaults/fidl.h" typedef struct _Location_raw { uint8_t pos_x; uint8_t pos_y; uint8_t pos_z } Location; Location Location_default = { 10, 20, 0 }; // Or in the source file. // May be used for memcmp, memcpy, etc. #define Location(my_instance) Location my_instance = Location_default;
// C code "example.c" #include <fidl.h> void showme(Location loc) { printf("(%u, %u, %u)\n", loc.pos_x, loc.pos_y, loc.pos_z); } int main() { Location(alpha); Location beta; Location gamma = Location_default; showme(alpha); showme(beta); showme(gamma); return 0; }
// Rust binding struct Location { pos_x: u8, pos_y: u8, pos_z: u8, } impl std::default::Default for Location { fn default() -> Self { Self { pos_x: 10, pos_y: 20, pos_z: 0 } } }
// Go binding, using export control type location struct { pos_x uint8 pos_y uint8 pos_z uint8 } Func NewLocation() location { loc := location{} loc.pos_x = 10 loc.pos_y = 20 // loc.pos_z = 0 Maybe ommited. return loc }
This change makes the FIDL file source backward-incompatible. No ABI or wire format change is needed.
It is not evaluated if implementation of this in all language bindings will be straightforward.
Protocol buffer, Flat buffer provides default values. Golang has a concept of zero values where variables declared without an explicit initial values are explicitly initialized as zero.
An open source approach
// From https://github.com/creasty/defaults type Sample struct { Name string `default:"John Smith"` Age int `default:"27"` Gender Gender `default:"m"` Slice []string `default:"[]"` SliceByJSON []int `default:"[1, 2, 3]"` // Supports JSON format Map map[string]int `default:"{}"` MapByJSON map[string]int `default:"{\"foo\": 123}"` Struct OtherStruct `default:"{}"` StructPtr *OtherStruct `default:"{\"Foo\": 123}"` NoTag OtherStruct // Recurses into a nested struct even without a tag OptOut OtherStruct `default:"-"` // Opt-out }