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