You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@groovy.apache.org by Jochen Theodorou <bl...@gmx.org> on 2026/08/31 16:39:20 UTC
GEP-31
Hi,
I just progressed on some work that was dangling for a really long time
and results are now in GEP-31
https://github.com/apache/groovy-website/blob/asf-site/site/src/site/wiki/GEP-31.adoc
This is not an implementation spec, it is not on purpose. It should be
enough to start an implementation and to discuss the general idea. I
think it has a lot of value. This is not really a new MOP or for
performance, this is more a story about protected a runtime or library
from unwanted changes in the meta class universe. One of my long term
goals is still a Groovy implemented 100% in Groovy... at least to make
it possible. Even static compilation in its current state will not make
this possible as extension methods may brake out into unrestricted
scopes. Imagine implementing MetaClassImpl in Groovy and then a DGM
wants to use the metaclass of MetaClassImpl for method dispatch. And now
think this extension method is used to get the target method. GEP-31 can
solve that problem.
```Groovy
@Realm(LIB_X_REALM)
@CompileStatic
class LibX {
...
}
```
with
`LIB_X_REALM = Core extensions + LibX extensions + isolated MetaClass
semantics`
then LibX does not suffer extension method pollution from another LibY
it depends on and just happens to be on the classpath. The static
compiler has a precise set of extension methods to consider, instead of
discovering them through the service approach we have right now, which
is generally open and depends on what I currently have on my compile
classpath. Since the extension methods are known at compile time now,
without a service lookup, the extension methods do not need to be
precompiled or discovered.
```Groovy
class Person {
String name
}
@RealmDef
LIBRARY_REALM = {
extends GROOVY_DYN
metaclass isolated
}
@Realm(LIBRARY_REALM)
class Library {
static void install() {
Person.metaClass.greeting = { "hello $name" }
}
static String run(Person person) {
person.greeting()
}
}
def person = new Person(name: 'Joe')
assert !person.metaClass.respondsTo(person, 'greeting')
use(LIBRARY_REALM) {
Library.install()
assert person.greeting() == 'hello Joe'
}
assert !person.metaClass.respondsTo(person, 'greeting')
```
Could be an interesting story for using meta programming in testing.
I also think this is groundwork for allowing a future new MOP and
especially experimental MOPs in a controlled way, without having to
exhibit it to the user. The realm specifies the MOP. It could be used to
enable a completely different MOP.
I would be interested in thoughts about this.
bye Jochen
Re: GEP-31
Posted by Jochen Theodorou <bl...@gmx.org>.
Hi Matt,
more inline
On 9/2/26 17:14, Matt M wrote:
> Hello,
>
>
> I read through the proposal and it sounds interesting. My initial
> impression is that it might not have a lot relevance to end users (maybe
> it does for specific library writers or as a kind of "constraint" around
> certain code? (I hesitate to say anything else or in other ways here in
> so far as to draw incorrect or unintended correlations)). In its current
> iteration, it seems focused on being a compiler level enhancement/
> requirement for future refactoring and redesigns than a necessarily
> highly applicable, broadly relevant user facing feature. None of which
> is bad.
yeah, I guess I was emphasizing the compiler part too much.
Some problems this tries to solve:
**Extension methods**
* In the static compiler, extension methods from a library dependency
can influence your code, even if you use nothing from that library.
* Extension methods are not available for internal use only. A library
cannot provide extension methods for its own implementation without also
making them available to users.
* Extension methods may have to be written in Java to avoid interference
from the MetaClass system.
* Users cannot define their own extension methods in the same way as
library-provided extension methods.
**Categories**
Categories are the user-level variant of extension methods, but their
scope is problematic because it is thread-bound.
* Most categories are actually intended to apply to a call site, which
is why this GEP discusses lexical categories.
* Dynamic categories complicate the implementation and affect every call
site that Groovy resolves dynamically. Being able to turn them off
permits a simpler and more reliable dispatch implementation, which also
benefits tooling and other implementations of the call site.
**Groovy core and Groovy modules**
* Some parts of Groovy core, such as extension methods and the MetaClass
implementation, cannot be written in Groovy itself without depending on
the dynamic mechanisms they implement. This is not a proposal to rewrite
Groovy in Groovy tomorrow, but currently there are places where this is
not possible at all.
* The old MetaClass system has accumulated several generations of
implementation techniques: reflection, generated call sites, primitive
optimizations, invokedynamic, and others. It needs a redesign that is
largely blocked by the requirement to preserve the legacy API.
**Optimized dynamic compilation**
This is already discussed extensively in the GEP. The basic idea is
dynamic Groovy with compile-time optimizations controlled by which types
and dynamic features are available.
For the user in short, more control, more tooling support under some
specific conditions, a new construct for categories.
> I believe I got the gist of the idea that the GEP is getting at. It
> would probably be really useful to call out and accentuate the exact
> purpose and mission statement of the problem(s) that it seeks to solve
> (e.g. "Start to work towards enabling strong encapsulation and isolation
> of dynamic capabilities in a controlled and deterministic way in so far
> as to prevent unintended leaks of the MOP and MOP-like functionality
> outside of an articulated scope.”).
the mission statement I would probably phrase along this:
The goal of realms is to make Groovy's dynamic semantics explicit and
controllable. A realm defines which dynamic capabilities are visible to
a piece of code, allowing extension methods, categories, the MetaClass
system, and other dynamic behavior to be selected, isolated, and
optimized independently of the surrounding application.
"which dynamic capabilities are visible to a piece of code" does not
mean encapsulation in the Java sense. This is not an OOP concept.
Optimization is a byproduct of having more control - control a human and
the compiler can understand.
Can a user continue writing his programs as before, most likely. The
intention is not to break existing code with this. I have to see if that
is actually realizable, but I think it should. And if there are changes,
then in the meta class api maybe.
> At a linguistics level for the idea, I think the term |Realm| is not
> quite a good fit for describing the concept. It's quite whimsical and
> stylized without quickly and clearly explaining/alluding to what pattern
> of functionality it represents or does, even colloquially. I would
> suggest changing it to some version or combination of the various
> explanatory terms/word-phrases already used in the GEP to explain/
> describe the idea itself such as |Environment|, |Scope|, |
> EnvironmentScope|, |ImmutableContext|, etc. just to name a few. For
> example, an initial idea of a clearer design that came to mind was that
> a |@Realm| (i.e. in usage form) is better described as a |@Scope| and a
> |@RealmDefinition| is described as an |@Environment|. Therefore, one way
> a user could think of it is as "You define an @Environment and then use
> that environment in/as a @Scope for code to execute in/under". Makes the
> mental model clearer and more explicit.
Names can still be changed, the concept is what needs acceptance first.
To give you an example of my impressions... When I hear scope, I think
block scope, variable scope and so on. Environment I think of a system,
environment scope I have no idea. If I had to do more with Kubernetes I
would probably associate realm with that world. Just see the names as
"work in progress".
> On a minor hiccup I had in my readings is the word "properties” being
> used. I initially got a little confused at how it was saying that these
> concepts would interact with and work with Properties (i.e. Groovy's |
> getters/setters|) since it said: "A realm inherits the definition of one
> other realm and may replace individual properties.”. I incorrectly
> conflated the term with the Groovy literal idea of |Properties| which is
> not what was intended. It might be better and clearer to say that what
> the GEP is referring to are environmental context attributes or
> something else of that kind.
For now I will then just use attributes, which really only works better
against Groovy and Java developers, because attributes is not used so
much there to describe fields.
> At a semantic level, overall, the GEP is going a bit deeper than the
> idea that might be canonically known as namespaces. It's closer to
> implementing specific resolution handling and isolation rules/semantics
> for strong encapsulation of/for the MOP. I tried to draw a corollary to
> other languages that implement the same concept or at least notionally
> seem to go for the same idea. The best one that that I could arrive at
> was idea of "function environments" in Lua. GEP-31 seems similar in
> vision albeit highly constrained on the MOP and extension methods
> exclusively in the current iteration.
Dart, Kotlin and Scala provide statically scoped extension mechanisms,
Ruby refinements are closer to lexical categories. JavaScript realms
instead isolate global execution environments. These mechanisms address
parts of the problem that realms address, but none combines them with
explicit control over Groovy's MetaClass-based dispatch.
Frankly the whole problem is home made and rooted in the complex MOP
[...]
> * How does backwards compatibility work in so far as the compiler’s
> public API/ABI is concerned? At first glance, it seems completely
> transparent and seamless. However, I wouldn't want it to be what
> project jigsaw was to Java (i.e. probably the least understood, most
> hated/disliked feature ever implemented in Java; that was largely
> seen as solely for the benefit of the compiler/language devs at the
> expense of everyone else). [I know that I am probably editorializing
> a fair bit here but based on my experience and interactions with all
> kinds of other developers in the Java space and even what the JVM
> architects said themselves, it's not really a disingenuous or even
> an unfair perspective].
well... good that you did not see some of the mails I exchanged with
those guys back then. That is all I will say about me not liking jigsaw,
or I will rant for a while.
I don´t think the ABI will change for this. I do not see where and what
for. There will be a new bootstrap method, to take the realm as
parameter, but the old one will continue to work and assume GROOVY_DYN
realm, which is 100% compatible to today.
> * What are rules for inheritance as it relates to a Realm and all of
> its layers' priority and ordering? How does a Realm inherit from
> another Realm and how do we envision that working (not from a syntax
> perspective but rather like how do we envision that actually working
> under the hood)? What is the mental model for its inheritance that
> is made clear for end users (folks in general struggle to understand
> OOP inheritance as it is already)? There's a lot of talk about
> layers and there seem to be quite many and they have various planned
> intricacies for how they each interact with each other and those
> above/below each other, in regards to precedence and priority.
Realms do not strictly inherit in the OO sense. A realm definition
declares capabilities. Extending another realm means taking those
capabilities and then overwriting selected ones with your own
definition. The resulting realm is an ordered composition of layers.
The usage side determines where the definition is applied. The usages in
the proposal are use(MyRealm) { ... } and @Realm(MyRealm). MyRealm is
more or less a token given to the runtime.
At runtime, that token is associated with an ordered list of layers per
class. The exact shape is not defined yet and will depend on the
implementation, but most likely there will be one layer per extension
method class, one for the small MOP, one for the extended MOP, and one
for mutable MetaClasses.
To dispatch a method, the runtime goes through the layers in order. Each
layer determines which targets are applicable; the applicable targets
may be empty. The most specific applicable method is selected as the
dispatch target. If no layer provides an applicable target, the dispatch
results in MissingMethodException.
Think of each layer as a specialist. We already have most of this
machinery in current Groovy, both as code and partially as a model - we
call it a meta class. The proposal separates the code paths and models
the dispatch environment more explicitly. Once it is represented as a
model, we can reason about it; with the current implementation, much of
that reasoning is implicit in the code. That combination of model and
code is currently spread between the meta classes and ClassInfo, as well
as several more classes.
> * How does access for Realms work? Are they public by default and/or
> can they be designated as private, package-private, etc.? Would
> protected be allowed?
I did not explicitly define that yet, yes. But since a definition will
be represented as class, it goes with the visibility of the class. And I
guess I should move the declaration style I used before to an explicit
class, where you can apply a modifier as well. Then simply normal class
rules apply.
> * What is the compelling use case/reason for a user to want to even
> use/know about/understand this feature at all? I would want to avoid
> it having the same kind of confusion and/or kind of general disdain/
> disinterest at understanding as there is/was around the JVM's
> concepts of classpath and modulepath interplay.
More control over the dynamic semantics of a piece of code.
A library can choose which extension methods, categories and MetaClass
behavior its code uses, without implicitly depending on whatever dynamic
environment happens to surround it. An application can do the same when
it wants a particular dynamic behavior or wants to isolate parts of the
application from each other.
Jigsaw mainly restricts what code can access. Realms do not primarily
restrict access. They let the programmer choose which dynamic
capabilities are present. There is isolation, yes, but there is no
*privileged* "inside" that needs to be protected from an "outside".
Think:
My library should behave the same way whether or not the application
happens to have some unrelated extension method or MetaClass
customization installed.
> * Are Realms repeatable/stackable (e.g. |@Realm(X) @Realm(Y) def
> my_method() { ... }|)? I could see it going either way on allowing
> or disallowing this. If allowed, there's then the challenge of
> checking for overlaps/conflicting extensions, precedence handling,
> and cycle detection that would have to be done at each usage site.
> If not allowed, then there's the challenge of how to allow users to
> compose Realms and/or extending Realms either that they didn't write
> and/or don't have access to.
|@Realm(X) @Realm(Y) def my_method() { ... }| is one usage site only.
But no, I would not allow that.
> At a syntax level, I know this will come off really blunt and harsh, I
> apologize in advance. I /really/ don't like the shape or design of the
> syntax for implementing a Realm's definition at all, as it is stated in
> the GEP. It looks very out-of-place and like non-idiomatic Groovy. It
> reads /very/ strangely and is awkward to understand at a glance since it
> seems like a hybrid of a not-closure closure and half a class
> declaration with a weird set assignment/definition thrown in for good
> measure. Syntactically, it's just very confusing to read/understand and
> I would imagine it will be quite kludge'y to implement at a grammar/
> syntax level as is. Again, I don't mean to draw the same parallel to
> jigsaw but it comes off as feeling like module-info.java all over again.
> Again, apologies for being really blunt and just hating on it.
you will be then surprised to hear that this requires not changes to the
syntax at all. Instead it is a DSL, a local transform changes the
semantics. I would probably now move the block into the annotation and
annotate a class that defines modifier and name. But I doubt that
changes your verdict. I am open for a better version of course. Only
that I do not want this definition to be a runtime construct. The result
should be readable without initializing the class it is based on.
> I think it would be simpler, clearer, and more consistent to not get
> clever at all with the syntax here and just be super boring about it by
> having it be implemented it as a typical plain-old Groovy class like
> anything else. Using common semantics like a constructor and a super
> class to clearly define the API contract of it all. The compiler could
> just scan for any and all classes that extend the super class (or
> implement a particular interface as that could be another route to go)
> and process those first/separately as environments/realm definitions.
> Sometimes simple and boring is best.
The class-scanning part is exactly what I do not want. A realm should be
an explicit semantic dependency, not something the compiler discovers by
scanning the classpath. Otherwise adding an unrelated realm to the
classpath can change compilation semantics, and incremental compilation
becomes harder to reason about.
I also do not want a realm definition to require class initialization or
object construction. The definition is metadata. I want the compiler and
runtime to be able to inspect it directly from the class file, using
reflection or ASM, and obtain the realm token without executing user code.
So a plain class can still be the underlying representation, but the
realm definition itself needs to be declarative and explicitly
referenced rather than discovered by scanning for subclasses.
The class is the discovery mechanism.
> At a conceptual level, I like the idea of what the GEP is shooting for
> in the broad strokes. There's some details to flesh out and refine. I
> think it would be really helpful as well to see a few illustrative
> examples and samples of the idea in motion so that someone could get a
> sense of what it enables, how it would work, and the value it adds for
> them and just getting a bird's eye view of it all.
**Library isolation**
```groovy
MY_LIB = {
extends GROOVY_DYN
extensions MyExtensions
metaclass isolated
}
```
and use `@Realm(MY_LIB)` for its implementation. The library then does
not accidentally acquire extension methods or MetaClass changes from the
application using it.
**Explicit extension dependencies**
Instead of discovering extension methods from everything on the
classpath, a realm explicitly declares them:
```groovy
MY_LIB = {
extensions [MyExtensions, SOME_OTHER_REALM.extensions]
}
```
**Lexical categories**
A category can be represented as a derived realm for a lexical region:
```groovy
use(MyCategory) {
// category semantics apply here
}
```
rather than changing thread-bound dynamic state. This is closer to how
categories are usually intended to be used, and it also gives the
compiler a known semantic environment for those call sites.
**Groovy itself**
The same mechanism allows different parts of Groovy to choose different
dispatch environments. For example, a new MetaClass implementation could
be used in a realm without requiring all of Groovy to use it
immediately. This is also the direction in which I see the realm concept
helping with a more optimized form of dynamic compilation.
Complete example would probably be too much for this mail.
> On a meta note, what Groovy version is this tentatively planned to
> target? I didn't see any mention of a target version but I would
> speculate v8 or v9 and beyond.
well... maybe Groovy 7 is too short. But nothing says that it has to be
complete in version 7.
> On a meta meta note, the original email came through just fine on my end
> and I even saw it on the mailing list archive too. Not sure that helps
> at all or anything but just throwing that out there. Emails/servers
> being wonky is one of the many fun caveats of old school mailing list
> style development.
I opened https://issues.apache.org/jira/browse/INFRA-28349 for this, and
we are both victims of this.
> I hope this is helpful. Thank you for writing this GEP up regardless.
The worst would have been nobody caring to even answer - so thank you
for caring! I think no good idea can be good enough if it cannot
withstand some skepticism.
bye Jochen
Re: GEP-31
Posted by Matt M <ma...@proton.me>.
Hello,
I read through the proposal and it sounds interesting. My initial
impression is that it might not have a lot relevance to end users
(maybe it does for specific library writers or as a kind of
"constraint" around certain code? (I hesitate to say anything else or
in other ways here in so far as to draw incorrect or unintended
correlations)). In its current iteration, it seems focused on being a
compiler level enhancement/requirement for future refactoring and
redesigns than a necessarily highly applicable, broadly relevant
user facing feature. None of which is bad.
I believe I got the gist of the idea that the GEP is getting at. It
would probably be really useful to call out and accentuate the exact
purpose and mission statement of the problem(s) that it seeks to solve
(e.g. "Start to work towards enabling strong encapsulation and
isolation of dynamic capabilities in a controlled and deterministic
way in so far as to prevent unintended leaks of the MOP and MOP-like
functionality outside of an articulated scope.”).
At a linguistics level for the idea, I think the term `Realm` is not
quite a good fit for describing the concept. It's quite whimsical and
stylized without quickly and clearly explaining/alluding to what
pattern of functionality it represents or does, even colloquially. I
would suggest changing it to some version or combination of the
various explanatory terms/word-phrases already used in the GEP to
explain/describe the idea itself such as `Environment`, `Scope`,
`EnvironmentScope`, `ImmutableContext`, etc. just to name a few. For
example, an initial idea of a clearer design that came to mind was
that a `@Realm` (i.e. in usage form) is better described as a `@Scope`
and a `@RealmDefinition` is described as an `@Environment`. Therefore,
one way a user could think of it is as "You define an @Environment and
then use that environment in/as a @Scope for code to execute
in/under". Makes the mental model clearer and more explicit.
On a minor hiccup I had in my readings is the word "properties” being
used. I initially got a little confused at how it was saying that
these concepts would interact with and work with Properties (i.e.
Groovy's `getters/setters`) since it said: "A realm inherits the
definition of one other realm and may replace individual properties.”.
I incorrectly conflated the term with the Groovy literal idea of
`Properties` which is not what was intended. It might be better and
clearer to say that what the GEP is referring to are environmental
context attributes or something else of that kind.
At a semantic level, overall, the GEP is going a bit deeper than the
idea that might be canonically known as namespaces. It's closer to
implementing specific resolution handling and isolation
rules/semantics for strong encapsulation of/for the MOP. I tried to
draw a corollary to other languages that implement the same concept or
at least notionally seem to go for the same idea. The best one that
that I could arrive at was idea of "function environments" in Lua.
GEP-31 seems similar in vision albeit highly constrained on the MOP
and extension methods exclusively in the current iteration.
In other words, as mentioned before, the idea is to start to work
towards a form of strong encapsulation and strong isolation for
Groovy's dynamic capabilities, specifically around extension methods
and the MOP. Some of the initial questions I had were:
- How does backwards compatibility work in so far as the compiler’s
public API/ABI is concerned? At first glance, it seems completely
transparent and seamless. However, I wouldn't want it to be what
project jigsaw was to Java (i.e. probably the least understood, most
hated/disliked feature ever implemented in Java; that was largely
seen as solely for the benefit of the compiler/language devs at the
expense of everyone else). [I know that I am probably editorializing
a fair bit here but based on my experience and interactions with all
kinds of other developers in the Java space and even what the JVM
architects said themselves, it's not really a disingenuous or even an
unfair perspective].
- What are rules for inheritance as it relates to a Realm and all of
its layers' priority and ordering? How does a Realm inherit from
another Realm and how do we envision that working (not from a syntax
perspective but rather like how do we envision that actually working
under the hood)? What is the mental model for its inheritance that
is made clear for end users (folks in general struggle to understand
OOP inheritance as it is already)? There's a lot of talk about
layers and there seem to be quite many and they have various planned
intricacies for how they each interact with each other and those
above/below each other, in regards to precedence and priority.
- How does access for Realms work? Are they public by default and/or
can they be designated as private, package-private, etc.? Would
protected be allowed?
- What is the compelling use case/reason for a user to want to even
use/know about/understand this feature at all? I would want to avoid
it having the same kind of confusion and/or kind of general
disdain/disinterest at understanding as there is/was around the
JVM's concepts of classpath and modulepath interplay.
- Are Realms repeatable/stackable (e.g.
`@Realm(X) @Realm(Y) def my_method() { ... }`)? I could see it going
either way on allowing or disallowing this. If allowed, there's then
the challenge of checking for overlaps/conflicting extensions,
precedence handling, and cycle detection that would have to be done
at each usage site. If not allowed, then there's the challenge of how
to allow users to compose Realms and/or extending Realms either
that they didn't write and/or don't have access to.
At a syntax level, I know this will come off really blunt and harsh, I
apologize in advance. I _really_ don't like the shape or design of the
syntax for implementing a Realm's definition at all, as it is stated
in the GEP. It looks very out-of-place and like non-idiomatic Groovy.
It reads _very_ strangely and is awkward to understand at a glance
since it seems like a hybrid of a not-closure closure and half a class
declaration with a weird set assignment/definition thrown in for good
measure. Syntactically, it's just very confusing to read/understand
and I would imagine it will be quite kludge'y to implement at a
grammar/syntax level as is. Again, I don't mean to draw the same
parallel to jigsaw but it comes off as feeling like module-info.java
all over again. Again, apologies for being really blunt and just
hating on it.
I think it would be simpler, clearer, and more consistent to not get
clever at all with the syntax here and just be super boring about it
by having it be implemented it as a typical plain-old Groovy class
like anything else. Using common semantics like a constructor and a
super class to clearly define the API contract of it all. The compiler
could just scan for any and all classes that extend the super class
(or implement a particular interface as that could be another route to
go) and process those first/separately as environments/realm
definitions. Sometimes simple and boring is best.
At a conceptual level, I like the idea of what the GEP is shooting
for in the broad strokes. There's some details to flesh out and
refine. I think it would be really helpful as well to see a few
illustrative examples and samples of the idea in motion so that
someone could get a sense of what it enables, how it would work, and
the value it adds for them and just getting a bird's eye view of it
all.
On a meta note, what Groovy version is this tentatively planned to
target? I didn't see any mention of a target version but I would
speculate v8 or v9 and beyond.
On a meta meta note, the original email came through just fine on my
end and I even saw it on the mailing list archive too. Not sure that
helps at all or anything but just throwing that out there.
Emails/servers being wonky is one of the many fun caveats of old
school mailing list style development.
I hope this is helpful. Thank you for writing this GEP up regardless.
Thanks,
Matt
------ Original Message ------
From "Jochen Theodour" <bl...@apache.org>
To dev@groovy.apache.org
Date 8/31/2026 4:45:47 PM
Subject Re: GEP-31
>
>
>Hi,
>
>
>
>forgot to send it from the apache.org account, because my normal account
>
>is not surviving the mailing list transformation properly and then gets
>
>marked as spam. That extends also to for example proton.me mails.
>
>
>
>Anyway, the original mail:
>
>On 8/31/26 18:39, Jochen Theodorou wrote:
>>
>> Hi,
>>
>>
>>
>> I just progressed on some work that was dangling for a really long time
>>
>> and results are now in GEP-31
>>
>>
>>
>> https://github.com/apache/groovy-website/blob/asf-site/site/src/site/
>>
>> wiki/GEP-31.adoc
>>
>>
>>
>> This is not an implementation spec, it is not on purpose. It should be
>>
>> enough to start an implementation and to discuss the general idea. I
>>
>> think it has a lot of value. This is not really a new MOP or for
>>
>> performance, this is more a story about protected a runtime or library
>>
>> from unwanted changes in the meta class universe. One of my long term
>>
>> goals is still a Groovy implemented 100% in Groovy... at least to make
>>
>> it possible. Even static compilation in its current state will not make
>>
>> this possible as extension methods may brake out into unrestricted
>>
>> scopes. Imagine implementing MetaClassImpl in Groovy and then a DGM
>>
>> wants to use the metaclass of MetaClassImpl for method dispatch. And now
>>
>> think this extension method is used to get the target method. GEP-31 can
>>
>> solve that problem.
>>
>>
>>
>> ```Groovy
>>
>> @Realm(LIB_X_REALM)
>>
>> @CompileStatic
>>
>> class LibX {
>>
>> ...
>>
>> }
>>
>> ```
>>
>>
>>
>> with
>>
>> `LIB_X_REALM = Core extensions + LibX extensions + isolated MetaClass
>>
>> semantics`
>>
>>
>>
>> then LibX does not suffer extension method pollution from another LibY
>>
>> it depends on and just happens to be on the classpath. The static
>>
>> compiler has a precise set of extension methods to consider, instead of
>>
>> discovering them through the service approach we have right now, which
>>
>> is generally open and depends on what I currently have on my compile
>>
>> classpath. Since the extension methods are known at compile time now,
>>
>> without a service lookup, the extension methods do not need to be
>>
>> precompiled or discovered.
>>
>>
>>
>> ```Groovy
>>
>> class Person {
>>
>> String name
>>
>> }
>>
>>
>>
>> @RealmDef
>>
>> LIBRARY_REALM = {
>>
>> extends GROOVY_DYN
>>
>> metaclass isolated
>>
>> }
>>
>>
>>
>> @Realm(LIBRARY_REALM)
>>
>> class Library {
>>
>> static void install() {
>>
>> Person.metaClass.greeting = { "hello $name" }
>>
>> }
>>
>>
>>
>> static String run(Person person) {
>>
>> person.greeting()
>>
>> }
>>
>> }
>>
>>
>>
>> def person = new Person(name: 'Joe')
>>
>>
>>
>> assert !person.metaClass.respondsTo(person, 'greeting')
>>
>>
>>
>> use(LIBRARY_REALM) {
>>
>> Library.install()
>>
>> assert person.greeting() == 'hello Joe'
>>
>> }
>>
>>
>>
>> assert !person.metaClass.respondsTo(person, 'greeting')
>>
>> ```
>>
>>
>>
>> Could be an interesting story for using meta programming in testing.
>>
>>
>>
>> I also think this is groundwork for allowing a future new MOP and
>>
>> especially experimental MOPs in a controlled way, without having to
>>
>> exhibit it to the user. The realm specifies the MOP. It could be used to
>>
>> enable a completely different MOP.
>>
>>
>>
>> I would be interested in thoughts about this.
>>
>>
>>
>> bye Jochen
>
>
Re: GEP-31
Posted by Jochen Theodour <bl...@apache.org>.
Hi,
forgot to send it from the apache.org account, because my normal account
is not surviving the mailing list transformation properly and then gets
marked as spam. That extends also to for example proton.me mails.
Anyway, the original mail:
On 8/31/26 18:39, Jochen Theodorou wrote:
> Hi,
>
> I just progressed on some work that was dangling for a really long time
> and results are now in GEP-31
>
> https://github.com/apache/groovy-website/blob/asf-site/site/src/site/
> wiki/GEP-31.adoc
>
> This is not an implementation spec, it is not on purpose. It should be
> enough to start an implementation and to discuss the general idea. I
> think it has a lot of value. This is not really a new MOP or for
> performance, this is more a story about protected a runtime or library
> from unwanted changes in the meta class universe. One of my long term
> goals is still a Groovy implemented 100% in Groovy... at least to make
> it possible. Even static compilation in its current state will not make
> this possible as extension methods may brake out into unrestricted
> scopes. Imagine implementing MetaClassImpl in Groovy and then a DGM
> wants to use the metaclass of MetaClassImpl for method dispatch. And now
> think this extension method is used to get the target method. GEP-31 can
> solve that problem.
>
> ```Groovy
> @Realm(LIB_X_REALM)
> @CompileStatic
> class LibX {
> ...
> }
> ```
>
> with
> `LIB_X_REALM = Core extensions + LibX extensions + isolated MetaClass
> semantics`
>
> then LibX does not suffer extension method pollution from another LibY
> it depends on and just happens to be on the classpath. The static
> compiler has a precise set of extension methods to consider, instead of
> discovering them through the service approach we have right now, which
> is generally open and depends on what I currently have on my compile
> classpath. Since the extension methods are known at compile time now,
> without a service lookup, the extension methods do not need to be
> precompiled or discovered.
>
> ```Groovy
> class Person {
> String name
> }
>
> @RealmDef
> LIBRARY_REALM = {
> extends GROOVY_DYN
> metaclass isolated
> }
>
> @Realm(LIBRARY_REALM)
> class Library {
> static void install() {
> Person.metaClass.greeting = { "hello $name" }
> }
>
> static String run(Person person) {
> person.greeting()
> }
> }
>
> def person = new Person(name: 'Joe')
>
> assert !person.metaClass.respondsTo(person, 'greeting')
>
> use(LIBRARY_REALM) {
> Library.install()
> assert person.greeting() == 'hello Joe'
> }
>
> assert !person.metaClass.respondsTo(person, 'greeting')
> ```
>
> Could be an interesting story for using meta programming in testing.
>
> I also think this is groundwork for allowing a future new MOP and
> especially experimental MOPs in a controlled way, without having to
> exhibit it to the user. The realm specifies the MOP. It could be used to
> enable a completely different MOP.
>
> I would be interested in thoughts about this.
>
> bye Jochen