-
Notifications
You must be signed in to change notification settings - Fork 53
Description
Currently when we convert a struct value v to a struct type T, any members of T that are missing in v get filled in with the default values of the member types. For example, in the definition
struct S { x: U32, y: F32 } default { x = 5 }
when we compute the default value of S, we convert the specified default value { x = 5 } to { x = 5, y = 0.0 } at type S, because 0.0 is the default value of the type F32. This rule has worked well so far, because the only place where we currently do this conversion is in computing default values of struct definitions (as in the example above), and this is the rule we want in that case.
However, @Kronos3 has pointed out that it's not an ideal rule once we introduce configuration parameters in templates. For example, if we had this configuration type
struct Config {
config1: U32
config2: F32
} default {
config1 = 5
config2 = 10.0
}
and we had a configuration parameter p of type Config, it would be nice to be able to bind { config1 = 3 } to p and have it become
{ config1 = 3, config2 = 10.0 }
instead of the current rule, which produces { config1 = 3, config2 = 0.0 }. That would allow us to use all the default values except for ones that are explicitly overridden.
We can specify this behavior as follows.
Type conversion: We can amend § 21.2.8 of the spec (https://nasa.github.io/fpp/fpp-spec.html#Evaluation_Type-Conversion_Structure-Values) to say that when we are converting a struct value with missing members to a struct type T, we use the corresponding members in the default value of T. For example, if the model contains this struct definition
constant c = { x = 1 }
struct S {
x: U32
y: F32
} default c
then converting {} to type S yields { x = 1, y = 0.0 }.
Computing default values in struct definitions: Section 5.13.2 of the spec (https://nasa.github.io/fpp/fpp-spec.html#Definitions_Struct-Definitions_Semantics) says that when computing the default value of a struct type T, we evaluate the specified default expression (if any) to a value v and then convert v to type T. Since converting to T now appeals to the default value of T, we will have to amend the specification to avoid circularity (appealing to the default value of T when constructing the default value of T). We can revise the algorithm as follows:
- Construct the “default default” value d of T. This is the value that is the default value of T if no default value is specified in the definition of T. It has the default value for each type at each member of T. (See https://nasa.github.io/fpp/fpp-spec.html#Types_Default-Values).
- If no default value expression e is specified in the definition of T, then use d as the default value of T. Otherwise (a) evaluate e to a value v; (b) convert v to the type of d yielding a value v'; and (c) convert v’ to the type of T yielding a value v’’. Use v’’ as the default value of T.
For example, for this struct definition
constant c = { x = 1 }
struct S {
x: U32
y: F32
} default c
we get the following:
- d is
{ x = 0, y = 0.0 } - e is
c - v is
{ x = 1 } - v’ is
{ x = 1, y = 0.0 } - v’’ is
{ x = 1, y = 0.0 } : S
There's no circularity in step 2(c) because there are no missing members in the value v'. So we don't need to appeal to the default value of T when converting v' to T. So we can do the conversion as part of computing the default value.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status