blob: 55b7b97e9dbbb4ab72b969a5a01c4f4437d15fcc [file] [log] [blame] [view]
# [FTP](../README.md)-003: Clarification: Default Values for Struct Members
Field | Value
----------|--------------------------
Status | Accepted
Authors | porce@google.com
Submitted | 2018-07-17
Reviewed | 2018-09-27
[TOC]
# Summary
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.
# Motivation
1. It provides regularity across the language binding, provides protections
from inconsistent or unexpected uses, and
2. Eliminates laborious manual, member-by-member initializations when a
language demands explicit initializations, and
Non-motivation includes:
* Saving bytes in wire format
It is *not* a motivation to save bytes in wire format or to save processing
power in doing encoding or decoding.
# Today's Implementation
Defaults can be [expressed][grammar] in the FIDL language on struct members:
* (+) There is support for numerical literals, boolean literals, and string
literals.
* (-) No type checking is provided by `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.
* (-) Language binding support is inconsistent, today it only exists for
C++, and Dart bindings.
There is no support for Go, C, or Rust.
For example (from [//zircon/tools/fidl/examples/types.test.fidl][example-types]):
```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";
};
```
# Design
Default values MAY be defined on struct members.
Defaults appear at the end of a field definition with a C-like `= {value}` pattern.
## Syntax
```fidl
// 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;
};
```
## Semantics
Please refer to [FTP-006](ftp-006.md) which clarified the semantics of defaults,
and requirements on bindings.
## Supported Types
* Primitive types:
* `bool`, `int8`, `int16`, `int32`, `int64`, `uint8`, `uint16`, `uint32`,
`uint64`, `float32`, `float64`
* Non-nullable `string`, `string:N`
* `string:N` shall zero out the memory that is reserved, and not used.
## Unsupported Types
* `array<T>:N`
* Set to zero
* Non-nullable types: `vector<T>`, `vector<T>:N`
* Set to zero
* Nullable types: `string?`, `string:N?`, `vector<T>?`, `vector<T>:N?`
* Set to null
* `handle`
* `struct`
* While each individual member in the `struct` may have a default,
a `struct` itself does not have a default.
* `union`
* To avoid any conflict, any default value of a member of the `union`,
or that of a substructure (in any depth) of the `union` shall be
ignored.
## Nuances of Defaults
The focus is on the value itself, and not on the *manner* of assigning the
value.
This implies two things at least:
* There is no distinction - if a default value is used because the parameter
of interest was explicitly assigned by another mechanism, or not.
* There is no extra (transparent) layer of logic to assign values at the
time of marshalling or unmarshalling.
# Implementation
Here are some example implemention ideas for C, Rust, and Go Bindings
```fidl
// 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
// 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
// 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
// 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 } }
}
```
```golang
// 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
}
```
# Backwards compatibility
This change makes the FIDL file source backward-incompatible. No ABI or
wire format change is needed.
# Performance
# Security
# Testing
# Drawbacks, alternatives, and unknowns
It is not evaluated if implementation of this in all language bindings will
be straightforward.
# Prior art and references
[Protocol buffer][proto3-defaults], 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
}
```
<!-- xref -->
[grammar]: /docs/reference/fidl/language/grammar.md
[example-types]: /zircon/tools/fidl/examples/types.test.fidl#45
[proto3-defaults]: https://developers.google.com/protocol-buffers/docs/proto3#default