Yes, that seems to go in the right direction. in other words... I would not know what to add to this and it looks very usable!

bye Jochen

On 6/17/26 12:10, Paul King wrote:
This is what AI suggests for BytecodeInterfacing. Is that the kind of
thing you had i mind?

package org.apache.groovy.lang.annotation; // next to @Incubating

@Documented
@Retention(RetentionPolicy.RUNTIME)              // matches
@Internal/@Incubating; enables a build-time check
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD})
public @interface BytecodeInterfacing {
     /** Groovy version whose compiler first emitted references to this
entry point. */
     String since();
     /** Groovy version that stopped emitting references; "" = still emitted.
         Set this when the compiler no longer generates the reference
but old bytecode still needs it. */
     String obsoleteSince() default "";
     /** Earliest Groovy version in which this may be removed (once min
supported bytecode passes obsoleteSince). */
     String removableIn() default "";
     /** Frozen JVM method descriptor, so a test can assert the live
signature never drifts. */
     String descriptor() default "";
}

   Why these choices:

   - Where: org.apache.groovy.lang.annotation, alongside @Incubating —
that's the established home for framework-level (non-transform)
annotations.
   - The version range is exactly Jochen's "introduced → no longer used
but still maintained." since + obsoleteSince captures the live span;
removableIn encodes the cleanup trigger so it's not lost. This
directly maps onto reality: staticArrayAccess would be since="2.5.0",
   obsoleteSince="6.0.0"; the v7 entry points since="2.5.0",
obsoleteSince="3.0.0"; bootstrap since="2.1.0" with no obsolete date.
   - RUNTIME + descriptor() unlocks the real payoff over a doc comment:
a tiny test (or extend the existing binary-compatibility subproject)
can reflect over all @BytecodeInterfacing members and assert the
descriptor still matches — so an accidental signature change to a
frozen method fails
   CI, while everything not annotated is understood to be freely
mutable. That's the enforcement @Internal can't give you.
   - It's orthogonal to @Internal/@Deprecated: a method can be
@Internal (don't call from source) and @BytecodeInterfacing (but the
signature is frozen for old class files). @Deprecated is wrong for the
live bootstrap — it's not deprecated, it's permanent-by-contract;
conversely
   fromCache/selectMethod are @Deprecated but not @BytecodeInterfacing,
which instantly tells you they're removable. That contrast is the
whole argument for a distinct annotation.

On Wed, Jun 17, 2026 at 8:46 AM Jochen Theodorou <[email protected]> wrote:

Actually I have one question...

Can we make all the indy callsite code, including IndyInterface
internal, to allow us to freely change the public method signatures?
Plus I was thinking that maybe we should add another such annotation,
that we could call BytecodeInterfacing or something like that, to mark a
method as directly called from compiled bytecode. Even better with a
version range for when it was introduced to when it was no longer used,
but still needs to be maintained to support older Groovy versions.

bye Jochen

On 6/16/26 14:53, Paul King wrote:
Hi folks,

I have just a few things to tidy up (maybe a day or two) then I plan
to do releases 5.0.7 and 6.0.0-alpha-2.

Let me know if you are working on something that should be included or
anything which we should wait for.

Thanks, Paul.


Reply via email to