gnodet commented on PR #12745:
URL: https://github.com/apache/maven/pull/12745#issuecomment-5436611779

   Thanks for the effort on this, @Hiteshsai007. The `api`/`implementation` 
split is a feature the community has been asking for, and it's worth getting 
the design right.
   
   Here are a few concerns and an alternative design proposal:
   
   ### Model version
   
   Changing the semantics of `compile` scope cannot land in model 4.1.0 — it 
would need to be model `>= 4.2.0`. The 4.1.0 model is already defined and 
changing existing scope behavior within it would be a breaking change to an 
established contract.
   
   ### Design concern: flipping `compile` semantics
   
   Making `compile` non-transitive and adding `api` as the transitive 
replacement inverts 20+ years of meaning. This creates a serious migration 
hazard: bumping `modelVersion` to 4.2.0 without migrating scopes would silently 
break runtime classpaths — everything compiles fine, then fails at runtime with 
`ClassNotFoundException`. The current consumer POM builder strips 
non-transitive scopes, so downstream consumers would lose those dependencies 
entirely.
   
   ### Alternative proposal: additive, not rename
   
   Instead of changing what `compile` means, introduce two **new** scopes 
alongside the existing ones:
   
   | Scope | Build paths | Transitive | Gradle equivalent |
   |---|---|---|---|
   | `compile` (unchanged) | compile + runtime + test | Yes | `api` |
   | `compile-only` (unchanged) | compile only | No | `compileOnly` |
   | **`api`** (new) | compile + runtime + test | Yes | `api` |
   | **`implementation`** (new) | compile + runtime + test | No | 
`implementation` |
   
   `api` is semantically identical to `compile` — it exists to express intent 
("this is part of my public API"). `implementation` is the new scope that 
provides the non-transitive behavior the PR is after. `compile` keeps its 
current meaning across all model versions — including as the default scope when 
`<scope>` is omitted.
   
   This is purely additive — no existing behavior changes, no silent breakage 
on model version bump, and no change to the default scope. Projects adopt 
`api`/`implementation` at their own pace.
   
   ### Phased rollout
   
   A concern with the additive approach is adoption — if the default doesn't 
change, there's no forcing function to get projects to use the new scopes. A 
phased rollout addresses this:
   
   **Model 4.2.0** — introduces `api` and `implementation` as new scopes. A 
model-level flag (e.g. `<defaultScope>`) controls the default scope when 
`<scope>` is omitted. The flag defaults to `api` (preserving today's transitive 
behavior). Early adopters can set it to `implementation` to get non-transitive 
defaults immediately.
   
   **Model 4.3.0** — the flag defaults to `implementation`. The default scope 
becomes non-transitive for everyone.
   
   The effective model builder already resolves undefined scope to `compile` — 
it would just need to check the flag and resolve to `api` or `implementation` 
accordingly.
   
   This gives projects three levels of adoption speed:
   1. **Conservative**: bump to 4.2.0, don't touch the flag — nothing changes
   2. **Gradual**: bump to 4.2.0, start using `api`/`implementation` explicitly 
on some deps
   3. **Aggressive**: bump to 4.2.0, flip the flag — get 4.3.0 behavior 
immediately
   
   ### Consumer POM compatibility
   
   The consumer POM needs to remain consumable by Maven 3.x. The scope mapping 
when downgrading to model 4.0.0 would be:
   
   - `api` → `compile` — exact semantic match ✅
   - `implementation` → `runtime` — consumers can't compile against it 
(correct), it's present at runtime (correct), slightly wider transitivity than 
ideal but safe ✅
   
   This means `api`/`implementation` should **not** force the consumer POM 
model version up — they have clean 4.0.0 equivalents. The 
`DefaultConsumerPomBuilder` would need a scope mapping table instead of the 
current `isTransitive()` filter, but no changes to Maven 3.x are needed.
   
   ### Migration via `mvnup`
   
   - **4.1.0 → 4.2.0**: no-op — new scopes are available, default behavior 
unchanged
   - **4.2.0 → 4.3.0**: for every dependency without an explicit `<scope>`, 
inject `<scope>api</scope>` to preserve transitive behavior. Developers can 
then tighten to `implementation` where appropriate. Projects that already set 
the flag or adopted `api`/`implementation` explicitly need no changes.
   
   This mirrors the migration path Gradle users went through when `compile` was 
deprecated in favor of `api`/`implementation`.


-- 
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]

Reply via email to