Paul King created GROOVY-12485:
----------------------------------

             Summary: Recognise Zazr control carriers by name in the monadic 
carrier allow-list
                 Key: GROOVY-12485
                 URL: https://issues.apache.org/jira/browse/GROOVY-12485
             Project: Groovy
          Issue Type: Bug
          Components: groovy-macro-library, groovy-typecheckers, Static Type 
Checker
    Affects Versions: 6.0.0
            Reporter: Paul King


h2. Background

GEP-23 ships a standard carrier allow-list 
({{org.apache.groovy.runtime.MonadicCarrierRegistry}}) shared by the {{DO}} 
runtime dispatcher, {{MonadicChecker}} and {{MonadicShapeChecker}}. Third-party 
libraries Groovy must not
depend on are listed by fully-qualified name: Functional Java ({{fj.data.*}}, 
{{fj.P1}}) and Vavr (ry/Either/Validation}}).

[Zazr|https://zazr.dev/] ({{dev.zazr:zazr-core}}, Apache 2.0, JDK 25+, no 
runtime dependencies) is er {{dev.zazr}} with the same four control carriers 
plus {{Lazy}}. All of them exposesingle-argument {{flatMap}}/{{map}}, so they 
already participate in {{DO}} via the structural path. However, structural 
participation is deliberately *untrusted*: 
{{MonadicChecker.trustedCarrierName}} returns {{null}} for it,
and {{MonadicShapeChecker.carrierFor}} only consults the registry and 
{{@Monadic}}. The result is tguarantees than the equivalent Vavr code.

h2. Observed behaviour (Groovy 6.0.0, zazr-core 0.4.0, JDK 25)

||Scenario||Zazr carrier||Same shape over Optional/Stream||
|{{DO}} over Option/Try/Either/Validation/Lazy under 
{{MonadicChecker}}|compiles and runs|compiles and runs|
|{{MonadicShapeChecker}} on {{Option.some(1).map \{ Option.some(it) 
\}}}|accepted silently, yields error: "did you mean 'flatMap'?"|
|Mixed carriers in one {{DO}} under {{MonadicChecker}}|compiles, then 
{{GroovyCastException}} at runtime|compile error: "Mixing carriers in a 
comprehension is not supported"|

Reproducer for the mixed-carrier case:

{code:groovy}
import dev.zazr.control.*
import groovy.transform.TypeChecked
import static org.apache.groovy.macrolib.MacroLibGroovyMethods.DO

@TypeChecked(extensions = 'groovy.typecheckers.MonadicChecker')
def mixed() {
    DO(x in Option.some(1), y in Try.success(2)) { Option.some(x + y) }   // 
should be rejected at
}
{code}

Reproducer for the shape-lint gap:

{code:groovy}
import dev.zazr.control.Option
import groovy.transform.TypeChecked

@TypeChecked(extensions = 'groovy.typecheckers.MonadicShapeChecker')
def nested() { Option.some(1).map { Option.some(it) } }   // M<M<T>>, no 
diagnostic today
{code}

h2. Proposed change

Add name-keyed rows to {{MonadicCarrierRegistry.NAMED_ENTRIES}}, using the 
structural {{flatMap}}/{ as the Vavr rows do:

{code:java}
// Zazr (dev.zazr) — recognised by name; no dependency. Structural flatMap/map,
// listed so the carriers are trusted by MonadicChecker and linted by 
MonadicShapeChecker.
new NamedEntry("dev.zazr.control.Option",     "flatMap", "map"),
new NamedEntry("dev.zazr.control.Either",     "flatMap", "map"),
new NamedEntry("dev.zazr.control.Try",        "flatMap", "map"),
new NamedEntry("dev.zazr.control.Validation", "flatMap", "map"),
new NamedEntry("dev.zazr.Lazy",               "flatMap", "map")
{code}

No new dependency and no behavioural change for any existing carrier. Because 
matching walks the tynested record cases ({{Option.Some}}, {{Try.Failure}}, 
{{Validation.Invalid}}, ...) resolve to their sealed parent as they do for 
{{fj.data.Some}} today.

h2. Scope of work

* {{MonadicCarrierRegistry}}: add the entries above and extend the class 
Javadoc.
* Tests: a {{ZazrCarrierTest}} in groovy-macro-library mirroring 
{{FunctionalJavaCarrierTest}}, usir {{dev.zazr.control}} (same pattern as the 
existing {{fj/data/Option.groovy}} stub) so the buildtakes no dependency. 
Cover: {{DO}} dispatch, {{MonadicChecker}} rejecting a mixed Zazr 
comprehension, {{MonadicShapeChecker}} reporting the three shape mistakes on a 
Zazr chain.
* Docs: {{_monadic-comprehensions.adoc}} allow-list paragraph; GEP-23 
allow-list and version historvy 6.0 release notes paragraph listing recognised 
libraries (if backported).

h2. Notes

* Zazr's {{Validation.flatMap}} short-circuits (its Javadoc says so; 
accumulation is via {{zip}}/{{ so {{DO}} semantics over it match Vavr and 
Functional Java {{Validation}}: dependent steps, firstfailure wins.             
                                                                                
                                                                                
                                       * Zazr's collections ({{Vector}}, 
{{List}}, {{LazyList}}) also have structural {{flatMap}}/{{map}};ft out, 
matching the treatment of {{io.vavr.collection.*}}.
* The user-configurable registration channel deferred to 7.0 by GEP-23 is the 
general fix for libraries Groovy does not know about; until it exists, 
extending the core allow-list is the only route for a type owned by another 
project.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to