Expand description
The value a Python member takes when the stream does not carry it.
Table 9 of DDS-XTypes 1.3, as Python. crate::default_c is the
same table as C, crate::default_java as Java, crate::default_cpp
as C++, crate::default_typescript as TypeScript, and
crates/wire-probe/src/default.rs is the reflective column’s; that
module carries the clause quotations and the reasoning for the three
kinds Table 9 does not list. Deliberately a sixth derivation and not
a call into any of them: the columns are compared against each other,
and a shared helper would make them agree about a mistake.
§Why it is a generated function and not a literal
A literal cannot carry an aggregate. “A structure without any of the optional members and with other members set to their default values” is a constructor call with one argument per required member, and writing that at every position a member can go missing would put the same answer in the generated file as many times as the type is reached — where two copies can differ. One function per type is one answer per type, which is what the C and Java columns do and for the same reason.
§Why it answers with the value instead of filling one
C’s defaulter is void zd_def_T(T *v): it writes through a pointer.
Python has no pointer and no out-parameter — rebinding a parameter
rebinds the local and nothing else — so the function returns
Table 9’s value and the caller assigns it, which is the same decision
one step later. It is also what makes the reader’s own shape work:
crate::emit::python::Python’s decoder opens with
v = zd_def_T(), so a position the stream does not carry is already
what Table 9 says before a single octet is read.
§What Python forces that TypeScript does not
A body is one return. Every other column fills a value member
by member, because it has something to fill: C writes through a
pointer, Java and TypeScript new an empty object first. A generated
Python aggregate is a @dataclasses.dataclass(kw_only=True) whose
required fields have no default, so S() is a TypeError and
there is no empty object to fill — the whole value is one call. That
is what adapter/python.rs meant by leaving the fields required, and
emit/python.rs’s reading_body says the same thing from the other
side.
Every argument is named. Two independent reasons, either of which
decides it. kw_only=True on the dataclass makes a positional
argument a TypeError outright; and adapter/python.rs builds the
field list from all_members_of, which flattens a base’s members in
front of the derived ones — so a positional list would silently
transpose two same-typed members if that order ever changed. Named,
a field that moves or is renamed is a TypeError at the call naming
the parameter.
An @optional member is left out of the call. §7.2.2.4.4.4.8’s
“Implementations shall not provide a default value” is the absence
here, and adapter/python.rs already declares such a field
typing.Optional[T] = None. Passing field=None would say the same
thing in a way that stops saying it the day the declared default
moves; leaving the argument out takes the declaration’s answer.
A union is one dataclass and not one arm per case.
adapter/python.rs declares _d beside one typing.Optional field
per case, so the value is U(_d=…, one=…) — or U(_d=…) alone where
the discriminator’s own default selects no branch, which Table 9
allows and which a Python dataclass can hold as it stands.
An enumeration’s default is the enumerator, written from the module
root. a.b.Colour.RED and not the number it happens to be: a
generated codec sits at the module root and adapter/python.rs nests
the enum.IntEnum in a class per IDL module, so RED there names
nothing at all. Through crate::emit::CodecTarget::enumerator_constant
rather than a second derivation, so the string is the one
emit/python.rs writes at every other site.
A long double is a Float128 and never a float. A Python
float is a binary64 with 53 significand bits and a long double is
a binary128 with 113, so a zero written as 0.0 would be a member of
the wrong type before any octet is read.
runtime/python/zerodds_wire/float128.py carries the sixteen octets
and Float128.zero() is its zero bit pattern.
A fixed<P,S> is a decimal string. Table 9’s zero for it is the
one spelling crates/wire-probe/src/canonical.rs accepts for that
scale — "0.00" for a fixed<5,2> — and not the empty string, which
is not a decimal at all.
A char and a wchar are a str of one. Table 9’s zero for a
character is the octet zero, which the C column writes as 0 and
this one as "\x00": Python has no character type, the member holds
a one-character str, and an integer there would be a different type
rather than a different spelling of one value.
A fixed array is that many elements, spelled out, as a tuple.
Python has no Array.from(…, () => …) and this tree has no
comprehension, and (zd_def_T(),) * n is the one form that must not
be used: it
evaluates the element once and repeats the reference, so writing
through element 0 of an array of aggregates would change all of them.
One call per element evaluates once per element. The cost is the
adapter’s already — adapter/python.rs writes tuple[T, …] with one
argument per element for the same array — and it is stated in both
places rather than hidden by a threshold at which the spelling
changes.
A typedef names the same defaulter as its target.
adapter::python::type_tag follows an alias through, so
defaulter_name answers zd_def_Point for Position as well —
and an alias arm that answered return zd_def_Point() would be a
function whose body calls itself. So a typedef is resolved before
the table is read, exactly as emit/python.rs’s value_type_of
resolves it, and the one function that results is the target’s.
Functions§
- default_
into place = zd_def_<T>().- defaulter_
from_ decoder - The defaulter that goes with a decoder, by name.
- defaulter_
name - The defaulter function name for a type.
- member_
default - One member’s default: its
@default, or its type’s. - python_
defaulters_ called_ by - The defaulters
declscall, and exactly those. - python_
defaulters_ over - Build the defaulter for each of
types, once per name.