1# Design Sketch: Initializer Values for Fields 2 3## Motivation 4 5It is often useful to initialize a structure to some "un-set" value before 6starting to modify it. For many structures, a simple `memset(buffer, sizeof 7*buffer, 0)` suffices, but other structures require specific values at specific 8locations, which are tedious to write out in user code. 9 10This design proposes two main elements: 11 121. A way to specify initializer values for specific fields. 132. A new feature in the generated C++ code to set the memory underlying a view 14 to those initializer values, or to 0 if no initializer was specified. 15 16 17## Initializer Value Syntax 18 19### Attribute 20 21The most straightforward option is to use the existing attribute syntax: 22 23 struct Foo: 24 0 [+2] UInt bar 25 [initialize_to: 7] 26 27The exact name TBD, but it should be somewhat visually distinct from the 28existing `$default` keyword for attributes, which specifies that an attribute 29should be used for all descendants of the current node, unless overridden: 30 31 [$default byte_order = "LittleEndian"] 32 33 34### New Syntax 35 36Other options might add new syntax. 37 38 39#### Suffix `= value` 40 41Suffix `= value` looks somewhat similar to the "initialize on construction" 42syntax in languages like C++: 43 44 struct Foo: 45 0 [+2] UInt bar = 7 46 47 class Foo { 48 int bar = 7; 49 }; 50 51However, it also looks somewhat confusingly similar to the field number 52specifiers in Proto: 53 54 message Foo { 55 optional uint32 bar = 7; 56 } 57 58 59#### Something Else? 60 61It is difficult to come up with a syntax that is clear and concise, especially 62to a reader who is not particularly familiar with Emboss: 63 64 struct Foo: 65 0 [+2] UInt bar := 7 66 67 struct Foo: 68 0 [+2] UInt bar [7] 69 70 struct Foo: 71 0 [+2] UInt [initialize to 7] bar 72 73Feel free to propose other options. 74 75 76## `Initialize()` Method 77 78Emboss *views* do not own their backing storage: creating a view does not 79allocate memory, it just provides a structured, well, view of existing bytes. 80This means that there is not a natural place to automatically initialize a 81struct, the way that there is for an object in a typical programming language. 82 83Instead, I propose adding an `Initialize()` method (name TBD) to each view, 84which can be called to explicitly initialize the underlying memory. 85 86For `external` (`UInt`, `Bcd`, etc.) and `enum` views, `Initialize()` should 87just set the initializer value specified in the `.emb` file, or `0` if none was 88specified. 89 90For structure views (`struct` and `bits`), `Initialize()` should set the 91initializer values of each of their fields, recursively. 92 93TBD whether `Initialize()` should also zero out any bytes that are not part 94of any concrete field. 95 96 97## Implementation Notes 98 99This is a moderately complex change, touching both the front end and C++ back 100end of the compiler, as well as the C++ runtime. 101 102 103### Front End Changes 104 105On the front end, adding a new attribute is definitely the most straightforward 106change: mostly just adding the new attribute to `attributes.py`, and updating a 107few things in `dependency_checker.py`, `expression_bounds.py`, and possibly 108`constraints.py` to inspect the new attribute. 109 110 111### C++ Back End Changes 112 113On the back end, there are a couple of implementation strategies. 114 115The easiest strategy is to generate an `Initialize()` method on each structure 116type that recursively calls `Initialize()` on each field within the structure 117(in dependency-safe order, similar to `WriteToTextStream()`). 118 119An alternate strategy would be to generate an "empty image" for each structure, 120and have `Initialize()` `memcpy()` the image into its backing storage. This 121seems like it would be faster at runtime, but may bloat binary size quite a bit 122-- a 4kb `struct` would need 4kb of const data in your binary to support 123`Initialize()`, whereas iteratively calling `Initialize()` on each element of 124an array does not require any extra code space for each element of the array. 125For this reason, there would likely still need to be a fallback to recursively 126calling `Initialize()`. 127 128Either way, fields with an explicit initializer value need to be wrapped in a 129view adapter when accessed, similar to how `[requires]` is handled now. 130 131Enum views can be generated with a simple `Initialize()` method that just sets 132their backing storage to 0. 133 134 135### C++ Runtime Changes 136 137Each of the views for Prelude types (`UInt`, `Int`, `Flag`, etc.) in 138`runtime/cpp/emboss_prelude.h` will need to have the new `Initialize()` method. 139