Designing generics for a new platform with no installed base, how do you decide whether type arguments survive to run time?
answer
- ask what the discard was ever for
- no installed base, no migration argument
- price the runtime, not the compiler
- who needs the argument while running
- a one-way door for the ecosystem
basics
~20 sWith no artifacts to stay compatible with, the strongest argument for discarding is gone, so the decision turns on the run-time bill against what library authors would otherwise pay to thread evidence by hand - and on the fact that the answer is close to irreversible.
solid answer
~40 sStart by noticing which argument you no longer have. Discarding is usually chosen to protect an installed base: one shared body, an unchanged runtime, artifacts that still link both ways. A platform with nothing deployed cannot spend that argument, so the choice is made on the remaining two columns. On the cost side, price the metadata per instantiation, the run-time system that must model parameterization, and the work of forwarding and comparing it on hot paths. On the benefit side, ask what your library authors will write: if the common patterns need code to act on the argument, every library pays that tax in its signatures forever. Then weigh irreversibility - once artifacts exist, both the compiled code and everything written against it assume the answer.
go deeper
The takeaway here is that the main reason platforms discard type arguments is compatibility with code that already exists, so a brand-new platform is not under that pressure.
Be able to state both columns: what keeping costs in metadata, runtime complexity and per-operation work, against what discarding costs library authors who must thread evidence through their signatures.
Show that you would price it against real target workloads and real library patterns rather than asserting a winner, and that you know a later reversal is an ecosystem migration, not a compiler flag.
This is the open trade-off you own: a one-way door whose cost falls on every library author or on every running program, with a conditional middle position that buys most of the benefit at the price of uniform rules.
## The argument you no longer have On a platform with history, the case for discarding type arguments writes itself: the installed base is already compiled, the run-time system is already shipped, and adoption has to be gradual. Remove the installed base and all three collapse. There are no artifacts whose shape must stay recognisable, no users to send a rebuild bill to, and the run-time system is being built anyway - so the expensive half of keeping arguments is being paid for regardless. This is the first thing a good answer says, because it reframes the question from *which is better* to *what is actually still being traded*. ## What is still being traded | Consideration | Argues for discarding | Argues for keeping | |---|---|---| | Run-time footprint | no metadata, no descriptors to store | willing to pay per instantiation | | Per-operation cost | nothing to forward or compare | acceptable on the paths that matter | | Library ergonomics | authors thread evidence explicitly | authors read the argument directly | | Guarantee at an unchecked inlet | none available | can be re-established while running | | Uniformity of the rules | one rule everywhere | one rule everywhere, at a price | | Interoperating with other platforms | shapes stay simple | distinct entities to map across | The row that decides it most often is **library ergonomics**, because it is the only one whose cost is paid over and over. A run-time bill is paid by the platform once in its implementation and then per operation; an evidence-threading tax is paid by every library author who needs the argument, in every signature, and then by every caller of those signatures, for the life of the ecosystem. ## Questions to answer before choosing 1. **What will the platform's libraries actually need to do with an argument?** If the common patterns are building values of the parameter, deciding behaviour from it, or re-checking something at an inlet, the workaround shows up in public signatures and never leaves. 2. **What does the run-time bill look like on this platform's target workloads?** Descriptor storage and forwarding matter differently for a long-running service, a short-lived program, and a constrained device. 3. **Who else has to interoperate with you?** Boundaries with other platforms and with data that outlives a process are where a richer run-time type model stops being purely your business. 4. **What do you want the rules to look like to a reader?** A uniform answer is easier to teach than a conditional one, whichever answer it is. ## Why it is close to irreversible The decision is not a compiler setting. Once the platform has users, the compiled artifacts in the field and the code written against them both assume the answer: - code written under discarding is full of explicitly threaded evidence, which a later change makes redundant but does not remove; - code written under keeping assumes it can act on the argument, which a later change breaks outright; - the run-time system's type model, its inspection surface and everything built on it are shaped by the answer. That is why platforms that started by discarding have generally kept discarding as the default, and why a designer should treat this as a one-way door and spend the analysis up front. ## The middle position, and what it costs A platform can keep the argument only where a declaration asks for it, paying the bill at those sites alone. It buys most of what library authors want without charging every program, which is genuinely attractive. What it costs is uniformity: the rules now depend on whether a declaration opted in, readers must know which kind they are looking at, and the opted-in form usually carries restrictions of its own that leak into signatures. Whether that is a good bargain is exactly the kind of judgment this question is asking for - there is no single right answer, and a candidate who claims there is has missed the point. ## What a strong answer sounds like It opens by naming the argument that no longer applies, prices both remaining columns concretely rather than in adjectives, identifies library ergonomics as the recurring cost and the run-time footprint as the standing one, and closes on irreversibility - the reason to decide it deliberately now rather than discover it later. An answer that simply asserts that keeping arguments is obviously better, now that compatibility is moot, has skipped the bill entirely.
- What evidence would you gather before making this call?Two things. What the platform's libraries will need to do with an argument, because a workaround there is paid in public signatures forever; and what the run-time bill looks like on the workloads the platform targets, since descriptor storage and forwarding land very differently on a long-running service and a constrained device.
- Is a middle position available?Yes - a platform can keep the argument only where a declaration asks for it, paying at those sites alone. That buys most of what library authors want without charging every program, but it splits the rules in two: readers must know which kind of declaration they are looking at, and the opted-in form tends to carry restrictions that leak into signatures.
- Why not start by discarding and add reification later if it is needed?Because the later change is not additive. Code written under discarding threads evidence by hand, which the change makes redundant but does not remove, and the run-time type model, the inspection surface and every tool reading it were built without the concept. You would be migrating an ecosystem, which is the bill the original choice was avoiding.
saying these in an interview costs you the question
- Argues the choice on elegance without pricing the run-time bill
- Assumes keeping arguments is obviously right once compatibility is moot
- Forgets the decision binds every artifact ever compiled for the platform
- Treats it as a compiler-only setting with no run-time consequence
- Claims discarding arguments is required to get one shared compiled body