This is an automated email from the ASF dual-hosted git repository.
paulk-asert pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/groovy-website.git
The following commit(s) were added to refs/heads/asf-site by this push:
new 28ee6f4 updated with recent changes
28ee6f4 is described below
commit 28ee6f4b479f77cc461560cae1b1263647edd2a7
Author: Paul King <[email protected]>
AuthorDate: Mon Jul 13 00:03:07 2026 +1000
updated with recent changes
---
site/src/site/wiki/GEP-27.adoc | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/site/src/site/wiki/GEP-27.adoc b/site/src/site/wiki/GEP-27.adoc
index b95ab65..a6381d9 100644
--- a/site/src/site/wiki/GEP-27.adoc
+++ b/site/src/site/wiki/GEP-27.adoc
@@ -14,7 +14,7 @@
*Comment*:: Reduces the per-closure/per-lambda generated-class explosion by
hoisting bodies onto the enclosing class. The sound-by-construction SAM-lambda
slice is merged for Groovy 6; closure packing (S1) is implemented and proposed
as a Groovy 6 stretch goal (GROOVY-12151); object elision and writer
unification remain for Groovy 7. Strictly additive; gated by a flag for
back-out.
*Leader*:: Paul King
*Created*:: 2026-07-09
-*Last modification*:: 2026-07-12
+*Last modification*:: 2026-07-13
****
[width="80%",align="center"]
@@ -410,7 +410,8 @@ closures rather than lambdas — now implemented in the code
generator (GROOVY-1
for Groovy 6.0 as a stretch goal. It covers the hard cases: no-capture and
captured closures (by
value; written captures via shared `Reference`, including `+=`/`++`),
*arbitrary-depth nested
closures*, implicit `it`, under both `@CompileStatic` and dynamic compilation,
correctly declining
-closures that use `delegate`/`owner`/`super`. All three safety mechanisms from
_Guarding the
+closures that use `delegate`/`owner`/`super`, or that carry default parameter
values (multi-arity —
+see _Excluded and deferred features_). All three safety mechanisms from
_Guarding the
dynamic trust assertion_ are implemented and validated: the mandatory
`PackedClosure` runtime
guard, the compile-time escape decline, and the `@PackedClosures(mode = WARN |
STRICT)` decline
diagnostics. The two headline capabilities are done:
@@ -459,6 +460,16 @@ proof and, for iteration intrinsics, knowledge of the
callee.
Fold the lambda and closure code paths behind the single hoist backend, so the
SAM and
`Closure` cases are one mechanism selecting different wrappers.
+A related follow-up surfaced in review: `MethodClosure` (from `.&` method
references) is the same
+shape — a `Closure` whose target is a known method that cannot honour a
delegate — but it dispatches
+by name with runtime overload selection and *silently ignores* a caller-set
delegate, whereas
+`PackedClosure` binds a fixed `MethodHandle` and *rejects* one. The two are
worth _contract_-aligning
+(a shared "known-target, delegate-inert" marker and consistent delegate
handling), and both could
+share the per-arity handle-selection primitive that default-parameter packing
(see _Excluded and
+deferred features_) also needs. Their dispatch models differ enough, though —
a fixed handle versus
+runtime overload selection — that fully merging them into one path is not a
goal; this is tracked as a
+separate initiative.
+
=== Default-on hardening
Flip closure packing from experimental (opt-in `groovy.target.closure.pack`)
to default-on. This is
@@ -693,6 +704,7 @@ stretch goal) builds on the shared backend proven in phases
1–2; phases 4–5
|Changing closure/lambda _semantics_ |Not planned |This is a codegen/packaging
optimisation only. Eligible closures compute identical results and keep their
reachable `Closure` API; ineligible ones are compiled exactly as today.
|Packing closures that use externally-set `delegate`/`resolveStrategy` |Not
planned |These require a real per-closure representation; they are detected
(statically) or declined and fall back to S0.
|Serializable closure/lambda hoisting |Deferred |Kept on the class-based path
initially; hoisting them requires carrying the deserialisation machinery to the
enclosing class.
+|Packing default-parameter (multi-arity) closures |Deferred |A single hoisted
method cannot reproduce the arity-overloaded dispatch a default parameter
generates, so these decline to S0 today. A future slice would hoist one method
per arity (reusing the existing default-fill codegen) and have the adapter
select a `MethodHandle` per arity at call time — the same primitive the
_MethodClosure_ alignment above would share.
|Object elision (S3) |Deferred (Groovy 7) |The most aggressive step; needs
escape proof and, for iteration, callee knowledge.
|Dynamic-mode automatic packing |Not planned |Cannot be proven sound without
types; dynamic packing is opt-in via `@PackedClosures` only.
|A user-visible switch between S1/S2/S3 per closure |Not planned |The compiler
picks the lightest sound representation; users influence it only via target
type, arrow syntax, and `@PackedClosures` — including opting a scope out
entirely with `@PackedClosures(mode = DISABLED)`, but never selecting *which*
packed representation is used.