skip to content

When is a value correctly serialized, given that the reader reconstructs a new value rather than receiving the original?

level: middleimportance: must knowfreq 58%

answer

  1. judged on the value, not the image
  2. encode, decode, compare declared fields
  3. two claims: value round trip, byte round trip
  4. symmetry is not agreement between implementations
  5. the equality used decides what passes

basics

~10 s

When decoding the bytes yields a value the application cannot distinguish from the original by any observation it makes. Correctness is round-trip equality over the declared fields, not byte-identity of the two memory images.

solid answer

~40 s

Correctness is defined by a **round trip**: encode the value, decode the bytes, and the result must be indistinguishable from the original in every way the application observes it — the declared fields compare equal under the type's own notion of equality. It is explicitly *not* identity of the two memory images, which will always differ, and it is *not* automatically byte-identity of a re-encode. Those are two separate claims: `decode(encode(v))` equals `v` is the usual correctness bar, while `encode(decode(b))` equals `b` is a stronger, separate promise that only some encodings make and that you need before bytes can be hashed or compared directly. The common trap is proving the first by running one implementation against itself, which shows self-consistency and says nothing about whether an independent reader agrees.

code

pseudocode · 13 lines
pseudocode
# claim 1 - value round trip: the ordinary correctness bar
copy = decode(encode(value))
assert declared_fields(copy) == declared_fields(value)
assert location_of(copy) != location_of(value)   # a new value, by construction

# claim 2 - byte round trip: a separate, stronger promise
bytes_in  = read(archive)
bytes_out = encode(decode(bytes_in))
assert bytes_out == bytes_in        # only some encodings promise this

# the check that is actually worth running
assert declared_fields(other_implementation.decode(encode(value)))
       == declared_fields(value)

go deeper

for a junior

Recall that correctness means the decoded value compares equal to the original on its declared fields. The two memory images always differ, and that difference is not a bug.

for a middle

Explain the two distinct claims — value round trip and byte-identical re-encode — and why an encoding can satisfy the first without the second when more than one byte sequence decodes to the same value.

for a senior

Show why a passing same-implementation round trip is weak evidence: a symmetric pair of mistakes passes it. Describe the cross check against an independently built reader and the edge values you would insist on feeding it.

for a principal

Decide what the correctness claim must cover for the organisation: which equality is authoritative, whether byte stability is required, and who is on the hook for proving an independent reader agrees.

## Correctness is a round trip, not a copy A decoder never hands back the original value. It builds a **new** value, in a different address space, at a different location, with the reader's own layout. So "did the serialization work?" cannot be answered by comparing memory. It is answered by a round trip: > Encode a value, decode the bytes, and the result must be indistinguishable from the original **by every observation the application makes of it**. That phrase does the work. "Indistinguishable" is relative to what the application looks at: the declared fields, compared under whatever notion of equality the type itself defines. Everything else — where it sits in memory, which padding bytes surround it, how much space it occupies — is not part of the value and is not part of the test. ## Two round trips, regularly confused There are two different claims, and they are not the same promise: 1. **Value round trip:** `decode(encode(v))` compares equal to `v`. This is the ordinary correctness bar, and it is what almost everyone means by "it round-trips". 2. **Byte round trip:** `encode(decode(b))` reproduces `b` exactly. This is a claim about the *bytes*, and it is the one you need before a payload can be hashed, signed, deduplicated or compared for equality without decoding. An encoding can satisfy the first and not the second. If two byte sequences decode to the same value — because a field could be written in either of two ways, or an absent field and a defaulted field decode alike — then re-encoding will pick one of them and the other will not come back. Whether an encoding promises a single byte form for a given value is a property of that encoding's design, and it is a design question in its own right; the point here is simply that assuming claim 2 because you have tested claim 1 is unfounded. ## The self-consistency trap The standard round-trip test runs the encoder and the decoder from **the same implementation**. What it can prove: - the implementation does not lose the values it was given; - the two directions are inverses *of each other*. What it cannot prove: - that the wire form is specified well enough for an independently written reader to agree; - that a reader built from a different description of the shape will reconstruct the same value; - that a value outside the tested range survives at all. A pair that is wrong in matching ways passes every such test. This is why an unreadable-by-anyone-else format usually ships with a green test suite: symmetry was verified, agreement was not. The stronger check is a **cross round trip** — one side encodes, an independently built side decodes, and the comparison is made on the declared fields. ## What is excluded from the check by design Not everything in a live value is supposed to survive. Anything that refers to a live resource of the writing process has no meaning on the other side and is deliberately outside the equality: - open handles and connections; - anything holding an exclusive claim on a resource; - entries that only make sense while a specific counterpart is alive. The round-trip check is therefore stated over the **declared** fields — the ones the wire contract says travel — and the excluded ones are re-established by the reader rather than compared. Stating that boundary explicitly is part of a good answer; silently comparing everything and then loosening the test when it fails is how the boundary ends up undefined. ## Where the equality itself goes wrong Two further ways a round-trip assertion lies: - **The wrong equality.** If the comparison uses identity rather than field-by-field equality, a correct decode fails; if it uses a loose equality that ignores a field, an incorrect decode passes. The test is only as strong as the notion of equality behind it. - **The unexercised range.** Round-tripping one well-formed example says nothing about empty collections, the extremes of a numeric range, absent optional fields, or text outside the common cases. Correctness claims live or die on the edges, and a round-trip test only covers the values you actually fed it. ## What an interviewer is checking The short answer they want is *round-trip equality over declared fields, not image identity*. The follow-up they are really waiting for is whether you know the test's limits: that same-implementation symmetry is not agreement, and that byte-identical re-encoding is a separate promise you must ask for rather than assume.

  • Your round-trip test passes but an independently written reader fails on the same bytes. What does that tell you?
    That the wire form is under-specified somewhere the two implementations disagree, not that the other reader is broken. A same-implementation test only proves the encoder and decoder are inverses of each other; two matching mistakes pass it. The useful signal is the exact field where they diverge, which names the part of the contract that was never written down.
  • Why is byte-identical re-encoding a stronger promise than value round-tripping?
    Because it constrains the bytes as well as the value. If more than one byte sequence decodes to the same value, re-encoding must choose one, and the others will not be reproduced. Value round-tripping tolerates that freedom; anything that hashes, signs or compares the payload without decoding it cannot.
  • Which parts of a value are deliberately left out of the round-trip comparison?
    Anything that refers to a live resource of the writing process — open handles, connections, exclusive claims — because they have no counterpart on the other side. The comparison is stated over the declared fields that the contract says travel, and the excluded parts are re-established by the reader rather than compared.

saying these in an interview costs you the question

  • Expects the decoded value to share the original's memory image
  • Treats a same-implementation round trip as proof of interoperability
  • Assumes value round-tripping implies byte-identical re-encoding
  • Compares by identity instead of field-by-field equality
  • Round-trips one happy-path example and calls the format correct