I have a few points to mention here:

(1) we could consider, and that is combined with some danger, to import specific classes only. import foo.bar.X does not have the same problem as import foo.bar.* for the performance of the compiler. The danger of course is that if X is no longer there, it would fail compilation even.

(2) I was wondering if we should copy a feature from python here and allow for something like:

import package java.util as u
assert u.List == java.util.List

we already have class aliases, this would kind of complete the picture.

(3) and this is building on top of (2) and a bit on (1)... let me call them virtual packages:

import package groovy.vp.calendar as CAL

def calendar = new CAL.Calendar.Builder()
                .set(CAL.Calendar.DAY_OF_MONTH, 11)
                .set(CAL.Calendar.MONTH, Calendar.JULY)
                .set(CAL.Calendar.YEAR, 2022)
                .set(CAL.Calendar.HOUR, 8)
                .set(CAL.Calendar.MINUTE, 30)
                .set(CAL.Calendar.SECOND, 00)
                .build()
def simpleDateFormat = new CAL.SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
println(simpleDateFormat.format(calendar.getTime()));

the idea is to have some container for classes, that is bound by feature, not by package structure. In this case SimpleDateFormat and Calender are both in the package groovy.vp.calendar, which is no real package and only contains the information that Calender is from java.util.Calender and SimpleDateFormat from java.format.SimpleDateFormat

Then you can have tailored packages like nio, nio2, collections, ...

(4) ha, so many crazy suggestions you think and you think I could not put one more on top? Wrong:

import groovy.vp.calendar.*

Now this is basically importing all classes from my virtual calendar package, namely Calendar and SimpleDateFormat.


Something general about class resolving...

I think I have to explain a bit about class resolving in Groovy in general. In the old times java was more dynamic than it was today. Back then You could have a jar X and a jar Y and both could declare classes in the same package. Practically this means if I import foo.* and do println Foo. I have to go through all class path elements and check if they define a package foo and if the package foo contains a class Foo - for each star import of course. And since it might be one time jar X and one time jar Y during compilation, heck both could define the class... it could be jar Z at runtime.

This is why in Groovy - which follows the tradition - additional star imports are expensive: # vanilla names * # classpath elements * # star imports. Only the situation is worse in Groovy since we decided to make classes and variables share the namespace. println foo could mean the class foo and we have to so maybe a 1000 search operations or a dynamic variable foo. Which is why lower case class names are not valid in Groovy anymore.

Ah yes. A import of a class full name would be resolved with this cost: # classpath elements. Which is significantly lower.

In newer Java versions one package can only reside in one jar. It does no longer allow these things on the module path and the class path then stays empty. Also they imply that module path at compile time equals module path at runtime, so there are no classloader shenanigans to consider. No the compiler can take all module path elements and make a big map (vanilla name -> full class name | Error) once and resolve all vanilla names in one go. Or you could see it as if the java compiler replace java.util.* with full name imports from java.util, like java.util.List.

My suggestion (1) goes in the same direction and with (4) building on top of that you get a similar version with similar performance and without relying on the module system.

bye Jochen

Reply via email to