A base type carries your rate-limit marker and a subtype declares none. When is that subtype treated as carrying the marker?
answer
- inheritance is opt-in
- declared on the marker, not the subtype
- type hierarchy, not redeclared members
- an override starts empty
- markers do not extend markers
basics
~20 sOnly when the metadata type itself is declared inheritable. Attachment inheritance is a property of the marker, not of the subtype, and it commonly reaches a subtype of a marked type while stopping at a redeclared member such as an overriding method.
solid answer
~50 sWhether an attachment travels down a hierarchy is decided by the metadata type's own declaration: a marker declared inheritable applies to subtypes of the type it was attached to, with the member values the base supplied; a marker that says nothing applies only where it was written. Two limits catch people out. The rule is normally about **type** hierarchies, so a method that overrides a marked method is a separate declaration and carries only its own attachments - the marker does not follow the override. And metadata types themselves generally cannot extend one another, so you cannot factor shared members into a parent marker; each metadata type stands alone and families are expressed by marking the markers. In a shared toolkit, both limits show up as a rate limit that quietly did not apply to the subclass somebody wrote last month.
code
pseudocode · 14 linesmetadata type RateLimited
targets: type, method
inherited: yes
mark RateLimited(permitsPerSecond = 10) // on the type
type PaymentOperations
mark RateLimited(permitsPerSecond = 5) // on the method
function charge(order) ...
type CardOperations extends PaymentOperations
function charge(order) ... // declares nothing of its own
// CardOperations -> marked (10), from the base type
// CardOperations.charge -> carries no marker at allgo deeper
Know that a marker does not automatically reach subtypes: whether attachments are inherited is something the metadata type has to declare.
Explain where the inheritance stops - a redeclared member such as an overriding method carries only its own attachments - and that metadata types do not extend one another.
Diagnose from the marker's declaration rather than the code that seems to be missing it, and show why an invisible inherited limit is a poor fit for anything that spends capacity.
Set the policy for the toolkit: which markers may be inherited at all, how collisions between an outer and an inner attachment resolve, and how teams are told what they inherited.
## Two different hierarchies, and the confusion between them The word "inheritance" means two unrelated things around metadata, and interview answers mix them constantly: 1. **Attachment inheritance** - a marker written on a base type being considered present on its subtypes. 2. **Metadata-type inheritance** - one metadata type extending another to share member elements. The first exists and is opt-in. The second generally does not exist at all. Keeping them apart is most of the answer. ## Attachment inheritance is declared on the marker If a toolkit wants "marking the base type limits every subtype too", the metadata type declares itself inheritable. Note what that means for responsibility: the decision belongs to the **author of the marker**, not to the author of the base type and not to the author of the subtype. A team writing a subclass cannot opt out of a marker they never wrote, and often cannot see it in their own file. Where the inheritance stops is the part worth knowing precisely: | Situation | Does the subtype's side carry it? | |---|---| | Subtype of a marked type, marker declared inheritable | yes, with the base's member values | | Subtype of a marked type, marker not declared inheritable | no | | Method overriding a marked method | no - the override is its own declaration | | Type implementing a marked interface | commonly no; systems differ here | | Field or nested member of a marked type | no | The row that costs production incidents is the third. An operation on the base type carries a limit; a subclass overrides it for a new payment provider; the override carries nothing, and the toolkit that reads per-method markers finds nothing to apply. Nothing failed, nothing logged, and the limit simply is not there. Note also that inheritance does not re-resolve members. The subtype is treated as carrying the **base's attachment**, values and all - it does not get a fresh attachment filled from the metadata type's defaults. ## Why metadata types do not inherit from one another The second kind of inheritance is the one people ask for after declaring their third marker with the same three members. They want a parent metadata type holding the shared members and three children adding one each. Metadata systems generally do not offer it, for a reason that follows from how markers are read: a reader asks a declaration whether a **specific named** metadata type is attached. Subtype relationships between metadata types would make that question ambiguous - is a declaration marked with a child also marked with the parent? - and every reader would have to decide whether to ask the exact question or the polymorphic one. What you get instead is composition at the meta level: mark the markers. Several markers can each carry a shared marker of their own, and a reader that looks one level up recognises the family. That gives grouping without giving a metadata type a supertype. ## Designing a shared marker around these rules 1. **Decide inheritability when you declare the type, and write down why.** It is invisible at the attachment site, so its effects are always at a distance. 2. **Prefer explicit attachments for anything that costs money or capacity.** A rate limit that appears by inheritance is a limit nobody reading the subtype's file can see. 3. **Do not design around markers following an override.** If the toolkit reads per-method markers, the override needs its own, and the codebase needs a check that says so. 4. **Factor shared members by convention, not by hierarchy.** Repeat the members and keep the names identical, or move the shared part up to a composed marker. 5. **Say what happens when both a type and a member carry the marker** - nearer wins, outer wins, or both apply - because inheritance makes that collision routine rather than rare. ## Diagnosing "the marker did not apply" When a marker seems not to have taken effect on a subtype, the questions are, in order: was the metadata type declared inheritable at all; was the attachment on the type or on a member of it; is the declaration you are looking at a redeclaration of something that was marked; and is the relationship in question a subtype relationship of the kind the system's inheritance rule covers. Four questions, all answerable by reading two declarations, and all of them about the **marker's** declaration rather than about the code that appears to be missing it.
- Why is an inheritable marker on a base type risky for a rate limit specifically?Because its effect is invisible where the cost lands. Someone reading the subtype sees no limit, someone reviewing the subtype's change sees no limit, and the limit is still applied - or, after an override, silently not applied. Capacity decisions are worth making visible at the site that spends the capacity.
- Three markers in the toolkit share the same three members. What do you do, given metadata types cannot extend one another?Keep the members duplicated with identical names and defaults so readers can treat them uniformly, and express the family by marking all three with one shared meta-level marker. Readers then ask one question one level up instead of knowing three names, and no supertype relationship is needed.
saying these in an interview costs you the question
- Thinks any marker on a base type applies to its subtypes
- Says an overriding method keeps the markers of the method it overrides
- Believes one metadata type can extend another to share members
- Treats inheritability as a property of the subtype's declaration
- Assumes an inherited attachment is refilled from the marker's defaults