Hi folks,

I'd like some feedback on GROOVY-12115 / PR #2645, specifically on the
config knob and its default. Quick framing first.

The problem: Because of erasure, various generic APIs require callers
to supply a type the compiler already knows. Classic example:

@CompileStatic
def demo(List<String> list) {
    def checked = list.asChecked(String)   // String is redundant -
the receiver is already List<String>
}

The fix: A new parameter annotation `@ClassTag` lets the static
compiler synthesize and inject that `Class<T>` argument from the
receiver's type arguments, so under `@CompileStatic`/`@TypeChecked`
you can just write:

def checked = list.asChecked()          // compiler supplies String.class

Synthesis only fires when the type is statically known (no `def`, raw,
or wildcard-only receivers). For this to work, we retrofit the
asChecked method by annotating the parameter we want to "disappear"
and be supplied automatically with `@ClassTag`. Prime retrofit
candidates are `asChecked` and `withDefault` / `withCheckedDefault`.

So far so good. But there are two flavours:

1. New/opt-in overloads - uncontroversial, you're choosing the tagged
method explicitly.
2. *Preemption* - this handles the case where both a tagged method and
non-tagged method could both match. If we automatically preferred the
tagged method, this would be a silent behaviour change, but it is
exactly what we sometimes want. So, it's currently gated behind a
config allowlist: `CompilerConfiguration.classTagPreemptionTargets`,
defaulting to just `withDefault`.

So the questions:

- Is a config-level allowlist the right mechanism for opting methods
into preemption, or would you rather preemption not exist at all
(opt-in overloads only)?
- If we keep it, is `withDefault` the right - and only - default?

My gut feel is leave as is, we can always add a system property or
dedicated commandline option later. And I think just "withDefault" to
start with. Anyone designing new APIs can just factor in ClassTag from
the start - it will only be where existing APIs exists and folks want
to retrofit the "reified" shorthand after the fact where more
allowlist items would be needed.

One forward-looking note: `@ClassTag` deliberately only reifies the
erased `Class`, which is all today's `isInstance`-style consumers
need. A fuller "TypeTag" tier carrying the complete generic signature
(à la Scala) could be a Groovy 7 conversation, but it's out of scope
here.

PR: https://github.com/apache/groovy/pull/2645
JIRA: https://issues.apache.org/jira/browse/GROOVY-12115

Cheers,
Paul

Reply via email to