paulk-asert commented on PR #3084:
URL: https://github.com/apache/groovy/pull/3084#issuecomment-6806281191

   Thanks James — your points on keeping the source lookup are fair, 
particularly javac parity. I'm happy for that to be the default on master, 
provided there's an opt-out just for the source part. I ran a few more checks 
against the current tip (`b96fa00c30`), comparing the option on and off:
   
   | Scenario                                                                   
                                          | Option off                   | 
Option on                                                                       
             |
   | 
--------------------------------------------------------------------------------------------------------------------
 | ---------------------------- | 
--------------------------------------------------------------------------------------------
 |
   | `GroovyShell` evaluates `new Timer()`, then parses a file `Timer.groovy`, 
then evaluates `new Timer()` again         | `java.util.Timer` both times | 
`java.util.Timer`, then `Timer`                                                 
             |
   | GSE runs `a.groovy` (`new Date()`); `Date.groovy` is then added to the 
root; `a.groovy` and a new `b.groovy` are run | all `java.util.Date`         | 
cached `a` gives `java.util.Date`, `b` gives `Date`, a fresh engine running `a` 
gives `Date` |
   | …then `Date.groovy` is deleted and `b.groovy` is run again                 
                                          | `java.util.Date`             | 
still `Date`                                                                    
             |
   | GSE root lookups for one script that uses 18 common JDK types              
                                          | 103                          | 139 
(two more per type, every compile)                                              
         |
   | `GroovyShell` whose parent class loader has a default-package 
`Random.groovy` resource                               | `java.util.Random`     
      | `Random`                                                                
                     |
   
   Two things follow from this:
   
   - **The full lookup also depends on what the loader has compiled before** 
(first row). `findByClassLoading` returns classes cached in the loader, so this 
happens with or without sources. I don't think it separates the two options, so 
I'd drop it as an argument for keeping sources. It's still worth a sentence in 
the notes, since groovysh, the console, and reused `GroovyShell`/GSE instances 
are affected.
   - **GSE is where the sources part hurts most.** A script records a 
dependency only on what it actually resolved to. A script that resolved `Date` 
to `java.util.Date` therefore never recompiles when `Date.groovy` appears in a 
root. A single engine ends up giving both answers, and a deleted source can 
stay in use. Groovlet or script names like `Calendar`, `Locale`, `Duration`, 
`Period`, `Year`, `Month`, `Clock`, `Instant`, `Proxy` or `Script` all fall 
into this.
   
   ### Proposal
   
   **1. A second option for the source part.** For example 
`DEFAULT_PACKAGE_SOURCES` (`defaultPackageSources`, system property 
`groovy.resolve.default.package.sources`). It only applies when 
`defaultPackageFirst` is on, and is on unless set to `false`:
   
   | `defaultPackageFirst` | `defaultPackageSources` | Lookup before the 
default imports                                                       |
   | --------------------- | ----------------------- | 
---------------------------------------------------------------------------------------
 |
   | `false`               | (ignored)               | none, the old order      
                                                               |
   | on                    | on (default)            | compiled classes and 
sources, as now                                                    |
   | on                    | `false`                 | compiled `.class` files 
only; sources still resolve after the default imports, as today |
   
   For the `false` case, please don't go through `resolveName` or 
`loader.loadClass`:
   - Use `loader.getResource(name + ".class")`, then `new 
DecompiledClassNode(AsmDecompiler.parseClass(url), new 
AsmReferenceResolver(resolver, compilationUnit))`, with the same name-mismatch 
check as `readClassFile`.
   - On a hit, `classNodeResolver.cacheClass(name, node)`; on a miss, cache 
nothing, so the later `resolveToOuter` still finds sibling sources.
   
   Keeping clear of `loadClass` also keeps the loader's cache, and so its 
history, out of it. It leaves GSE's `findClassNode` override, and therefore its 
roots, alone.
   
   **2. GSE default (optional, your call).** Consider having 
`GroovyScriptEngine` default `defaultPackageSources` to `false` unless the 
caller sets it. That avoids the mixed and stale results above without changing 
`groovyc` or the `groovy` command. If you'd rather keep one default everywhere, 
please document the GSE behaviour in the notes instead.
   
   **3. Gradle isn't affected by the source opt-out.** In an incremental build 
the classes Gradle doesn't recompile are `.class` files in the output 
directory, so the class-only lookup finds them. Source directories aren't on 
the compile class path. The stashed-class loaders in gradle/gradle#39622 don't 
change this: `CompileClasspathGroovyClassLoader` hides stashed classes from 
resolution, and those classes are in the compilation unit anyway. Either 
setting therefore gives the same full-vs-incremental result in Gradle.
   
   **4. Tests.**
   - Extend `Groovy12555` with the sources-off case: a compiled sibling still 
shadows the default import, and a source sibling no longer does.
   - Add a GSE case: a root source shadowing a default import with the default 
settings, and not with sources off. Assert whichever GSE default you pick.
   
   **5. Notes.** Update `COMPATIBILITY.md` (the Groovy 7 and 6.0.1 entries) and 
`core-program-structure.adoc` for the new option, with the Gradle route 
`groovyOptions.optimizationOptions['defaultPackageSources']`. Also cover GSE's 
mixed old and new results and stale results until the engine is recreated, the 
two extra root lookups per type under GSE, and the loader-history point above. 
The 6.0.x port would carry both options, both off by default there.
   
   **6. Housekeeping.**
   - Daniel's approval was for `14288a89`. The later commit, which applies the 
lookup to qualified nested names (`testModuleImports` → `testDefaultImports`), 
needs a quick re-review.
   - The branch now conflicts with master in `COMPATIBILITY.md` and in the 
system-property table in `CompilerConfiguration`'s Javadoc. Both are 
straightforward: keep both sides.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to