daniellansun commented on PR #2736:
URL: https://github.com/apache/groovy/pull/2736#issuecomment-5133665005
@blackdrag Thank you — this is exactly the right question, and your A/B/C,
D/E, F/G scripts make the boundary sharp.
### Short answer
Hierarchy SwitchPoint fan-out is needed in **one** live-selection situation
only:
> The **receiver’s MetaClass is unchanged**, selection previously linked a
result that depended on an **ancestor** modified `MutableMetaClass` (almost
always EMC) via the **missing-method** walk
(`MetaClassImpl.findMethodInClassHierarchy`), and that ancestor later **gains
or loses** methods that change the walk’s result.
Concrete dual:
| Already-linked site on child | Parent MetaClass event | Without hierarchy
SP | With hierarchy SP |
|---|---|---|---|
| Miss for name `m` | Parent EMC adds `m` | Stale miss | Re-link → hit |
| Hit found only via parent EMC | Parent EMC removed / replaced away | Stale
hit | Re-link → miss |
That is **all** hierarchy SwitchPoint is for. It is not a general “parent
MetaClass version” for child tables, and it does **not** rebuild a child’s
method index.
### Mapping your examples
They are consistent with that rule; most of them **do not** require
hierarchy SP:
1. **Present method on the child** (your `B.m2` / declared `foo` cases)
The hierarchy walk does not open for that applicable name/signature.
Parent mutation is **not** required for correctness of the *present* method. We
may still over-invalidate subtype domains when parent EMC mutates (monomorphic
domain trade-off), but that is over-invalidation, not a semantic necessity for
those names.
2. **Construction-time / EMC snapshot** (D/E after `removeMetaClass(E)`, F/G
after `removeMetaClass(F)`)
The more specific method is already **copied into the child’s MetaClass
instance**. Parent replace/remove does not change that instance’s tables.
Hierarchy SP cannot and should not “undo” a snapshot. Replacing the **child**
MetaClass is what rebuilds the view — exactly as in your D/E ladder.
3. **User-surprising B vs C blocking** (`B.m2` blocks more-specific `A.m2`
for `B` receivers, not for `C`)
Agreed this is awkward from a user POV. It is a property of the
missing-method walk / “present method wins” rule, not of SwitchPoint scoping.
We are **not** redefining that MOP rule in this PR.
4. **The case that *does* need hierarchy SP** (what the machinery is for):
```groovy
class Parent {}
class Child extends Parent {}
def call(x) {
try { x.onlyOnParent(); 'hit' }
catch (MissingMethodException e) { 'miss' }
}
def c = new Child()
assert call(c) == 'miss' // monomorphic miss linked on Child
Parent.metaClass.onlyOnParent = { -> 'now-visible' }
assert call(c) == 'hit' // must re-select; Child MetaClass
unchanged
```
and the inverse (linked hierarchy hit → parent EMC removed → miss again).
Same pattern for `Object.metaClass.foo` / interface MetaClass / `Object[]`
lattice.
Without fan-out, those already-linked subtype sites stay wrong until
something else retires the child’s domain.
### “A lot of machinery for a small feature”
Fair point. The *feature* is small in description (missing-method hierarchy
+ EMC), but it is the same feature that makes `Object.metaClass.foo = …` /
parent EMC methods visible on subtypes without giving every subtype its own
EMC. For 6.0 we **keep** that MOP observation path (so hierarchy SP stays as
its invalidation counterpart). Pure unmodified `MetaClassImpl` ↔
`MetaClassImpl` (or null) replace stays **exact-class only** — no hierarchy.
What we *did* simplify on the domain side (current tip of this PR):
- SwitchPoints are per **MetaClass instance** (weak identity map in
`IndyInvalidation`), not a process-wide SP and not a permanent ClassInfo
“generation” dual to MetaClass.
- `ClassInfo` only has a **pending** domain for pre-MetaClass link
(defineClass safety); first MetaClass install retires it.
- Hierarchy fan-out remains indexed (`ClassHierarchyIndex`) and
MetaClass-aware (EMC / modified mutable / interface / array / global EMC →
fan-out; hierarchy-local `MetaClassImpl` pairs → exact).
So hierarchy logic is not “version every parent change for every child
site”; it is “when parent can change what a **linked miss/hit on the
missing-method path** means, re-select subtype sites.”
### Bottom line
| Question | Answer |
|---|---|
| Must parent MC change invalidate a site if the receiver MC is unchanged? |
**Only** if selection can still change via the live missing-method hierarchy
walk (linked miss↔hit against an ancestor modified `MutableMetaClass` / EMC,
including interface/array lattice). |
| What is hierarchy SP trying to solve? | Keep already-linked **subtype**
indy sites honest for that walk — nothing else. |
| Snapshots / present methods / EMC copies? | Not hierarchy SP’s job; they
stay until the **receiver** MetaClass is replaced or rebuilt. |
Happy to tighten docs or tests further if any row of this matrix still
disagrees with the behaviour you want for 6.0.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]