Skip to main content

Module default_python

Module default_python 

Source
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 decls call, and exactly those.
python_defaulters_over
Build the defaulter for each of types, once per name.