skip to content

Which constructs would you keep out of a shared IDL contract that several ecosystems generate readers from, and why?

level: middleimportance: should knowfreq 42%

answer

  1. model in the IDL's type system
  2. if you must name a runtime, it leaked
  3. runtime-typed polymorphism forces per-target dispatch
  4. ordering and key rules must be declared
  5. reserved words mangle generated identifiers

basics

~10 s

Keep out anything whose meaning is borrowed from one ecosystem's type system: runtime-typed polymorphism, deep or recursive nesting, collections whose ordering or key rules differ, and names that collide with a target's reserved words.

solid answer

~50 s

A contract shared by several ecosystems must be expressible in the IDL's own type system, not be a projection of one language's. The constructs that cause trouble are the ones a generator has to approximate differently per target: inheritance hierarchies resolved by a runtime type name, which force each generator to invent its own dispatch; deeply nested or recursive structures, where generated accessor ergonomics and stack safety diverge; collections whose ordering or key equality is assumed rather than declared; and field names that collide with a reserved word or a naming convention in some target, so the generated identifier differs per ecosystem even though the wire key does not. The rule of thumb is a good answer to give: if you have to name a runtime to explain what a field means, the contract has leaked.

go deeper

for a junior

Recall that a shared contract is compiled for several languages, so it should describe data rather than mirror one language's classes.

for a middle

Explain which constructs a generator must approximate differently per target — runtime-typed polymorphism, unbounded recursion, assumed collection semantics — and what to model instead.

for a senior

Show the review discipline: judge each construct against targets that do not exist yet, and explain why the cost of fixing a leak rises sharply once several teams have generated against it.

for a principal

Decide how strict the contract's house style should be, and who owns it, given how many ecosystems the organisation must keep genuinely equivalent.

## The rule under all of the specifics A contract compiled for several ecosystems must be **modelled in the IDL's own type system**. Whenever a construct's meaning comes from one language, the generator for every other target must approximate it, and the approximations differ — which means consumers disagree about what the same bytes mean. The single test worth remembering: *if explaining a field requires naming a runtime, the contract has leaked.* ## The constructs that leak - **Runtime-typed polymorphism.** A field declared as "some subtype, identified by a type name written into the payload" asks every generator to invent a dispatch mechanism and forces every consumer to share the producer's class taxonomy. It is also the construct most likely to turn a decoder into an object factory driven by untrusted input. Model the alternatives explicitly instead — a declared, closed set of variants with an explicit discriminator field, so every generator emits the same choice. - **Deep or recursive nesting.** A record that contains itself to arbitrary depth is expressible in most IDLs, but generated accessors for it diverge sharply, and a decoder's recursion behaviour on a hostile input is not uniform. Flatten to a list with parent references when the depth is genuinely unbounded. - **Collections whose semantics are assumed.** "A map" hides three questions: is iteration order part of the contract, which key types are permitted, and what happens on a duplicate key? Ecosystems answer all three differently by default. State the answer in the contract, or use a repeated record of explicit key/value pairs when order or duplicates matter. - **Identifier collisions.** A field name that is a reserved word in one target, or that differs from another field only by case, forces that generator to mangle the identifier. The wire key is unaffected — the contract still says what it said — but the generated name differs per ecosystem, which is confusing in review and invisible until someone adds the affected target. - **Types whose only definition is a runtime's.** Any field whose meaning is "whatever that ecosystem's native type does" — including free-form blobs that consumers are expected to decode with their own native mechanism — is a contract in name only. ## What belongs there instead | Leaky construct | Neutral modelling | |---|---| | Subtype chosen by a runtime type name | closed variant set with an explicit, declared discriminator | | Unbounded recursive record | flat list of records carrying a parent reference | | Map with assumed ordering | repeated key/value records, order stated in the contract | | Free-form native blob | declared record, or bytes with a stated encoding and owner | | Name colliding with a reserved word | a name chosen to survive every target's conventions | ## Why this is a review property, not a coding one These defects are cheap to fix in the contract and expensive to fix after generation, because by then several teams have generated against them. That makes them the core of a contract review: a reviewer is not asking "is this field useful", but **"does this mean exactly one thing in every ecosystem that will compile it, and can the generator for a target we have not added yet express it?"** The forward-looking half matters. A contract is usually written when two ecosystems consume it and lives long enough to reach four. Constructs that were fine for the original pair — because both happened to share a convention — become the reason the fourth consumer's reader is subtly different. Ecosystems genuinely differ on how they represent absent values, how they order collections, and whether they can express unsigned or arbitrary-precision numbers at all; the contract's job is to say which behaviour is required, so no generator has to guess. ## The pragmatic counterweight None of this argues for a contract so minimal it is useless. Nested records, enumerations, repeated fields and optional fields are all expressible everywhere and should be used freely. The line is not "avoid structure", it is **avoid structure whose meaning is inherited from one implementation**. A contract that can be read by someone who has never seen the producer's source, and implemented by a generator for a target that did not exist when it was written, is the target to describe in an interview.

  • A contract must carry one of several payload shapes. How do you model that without runtime-typed polymorphism?
    Declare a closed variant: an explicit discriminator field with a declared enumeration of cases, and one declared record per case. Every generator emits the same structure, a reviewer can see the whole set, and a decoder never constructs a type chosen by the sender. Adding a case is then a visible contract change rather than a deployment somewhere else.
  • Does a reserved-word collision in one target change the bytes on the wire?
    No. The wire key is whatever the contract declares; only the generated identifier in that one ecosystem is mangled by its generator. It is an ergonomics and review problem, not an interoperability one — but it is worth avoiding, because the mangling rule is the generator's choice and may change between generator versions.

saying these in an interview costs you the question

  • Writes the contract by transliterating one language's classes
  • Assumes every ecosystem can express unsigned or arbitrary-precision types
  • Treats map iteration order as guaranteed across readers
  • Models variants as a runtime type name in the payload
  • Believes an identifier collision changes the wire key