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