When writing type-level code (and to a lesser extend always) complex types tend to accrue a lot of constant prefixes. Could the compiler, when reporting errors, at reaching a certain threshold (type length as a string, number of referenced types/number of types from a single package, number of occurrences of the same type - to be decided) add import clauses before/after the error report, and reference the types in the report through those imports? This would immensly improve the readability of the report. In many cases, this would only add a single line, as a great chunk of all code deals with classes from the same package which could be imported together with the brace syntax.
What is the view of movers and shakers on this feature? Does it look like a possible first issue? If such a change would be welcome and someone pointed me in the right direction, I could perhpaps give it a go.
In the vast majority of practical applications, all types could be imported at the very least to their most-outer anchored path element (class/object).
So
The aggresiveness of importing is of course a matter of debate, but I would lean towards importing everything down to the shortest unique suffix. The fact that the āimport sectionā grows is of little relevance, as in most cases there would be no need for the programmer to even look at it, as the location in the code and locally unique type names should be uniquely mentally resolvable.
Of course, fine tuning makes sense - perhaps refrain from importing type aliases, or member types. But even stripping the redundant packages would considerably improve readability.
The same mechanism would be extremely useful in pretty-printing program fragments, in the context of metaprogramming, or program dumps by the compiler.
We just need a mechanism to compute maximal import statements without introducing any ambiguities (we should not import the same names several times), and this mechanism could be reused in error messages, code pretty-printing, and compiler dumps.
Perhaps the compiler could use the same imports used in the source file, since those are the ones that are most natural to Scala users. However, when it comes to stuff inside a different source file or inside a jar, Iām not sure how that would work.
IntelliJās approach might be a useful source of inspiration here.
When generating a type annotation to a method, they try to get it down to a direct import. Thatās not always possible so in the case of a naming collision they import the longest possible prefix.
For example, adding a type annotation to a method which returns a scala.collection.mutable.Map would generate an import statement for scala.collection.mutable and the type added would be mutable.Map.
So if the compiler preferentially takes the imports in the file (optimizing for familiarity), and gives a best-effort at maximizing imports for types that donāt already have them (optimizing for readability), it should produce very readable results. There are some corner cases, as itāll occasionally annotate a String as _root_.java.lang.String - usually when itās a nested type parameter, however I think the approach is pretty reasonable.
This would indeed be awesome, as it would resemble the offending code the most. I do not know though if this kind of information is retained at the point of generating a report (because the best place to introduce this is late, so it covers all bugs, not only from the typer? - discuss). Or can it this information be somehow linked again at this stage?
@morgen-peschke - your Map example relies on the configurable set of ānever directly import types from this packageā. Does making it a compiler parameter make sense? The algorithm you describe (regardless if with the first stage or without it) sounds extremely simple. Two issues I am not sure about are:
renaming imports in the source file (would be great to honour them, will that information be available?
type aliases resolving to the same type; I vote thay should stay as they are, without being resolved; Double imports arenāt allowed, are they?
@LPTK - what ambiguities do you have in mind? Simply importing different entities with the same name but different package, or something I am unaware?
The āmaximal path without ambiguities based on scala.reflect.runtime.universe.Typeā seems not difficult and I assume is directly applicable to compiler internals. Not trivial because of kinds - I have no idea how T(some other), [O] some.class[O(in method m)] or existentials are modeled. Probably solvable by simply trying that out, though.
I know nothing however about where to look for imports of the relevant file and how the message printing API looks like. For all I know, the task may be basically impossible, if parts of the messages are constructed at usage site.
If someone in the know opinionates that its doable and points me at least to the place where it should be implemented, I could give it a go. It would need some serious code review and input on test cases though - I donāt know how complete my code would be, as I am very likely to miss some cases (I have no idea what they even look like ATM).
Also: is anyone here familiar with scaladocs and if the same APIs apply? I would be even more interested in making links using imports from the source file work, as it would undoubtedly lock in my place in the heavens.
Map was probably a bad example for what I was trying to convey. That being said, having a configurable list of ānever truncate types further than this packageā would probably be useful.
Iāll give describing what IntelliJ does another shot:
Assuming the existence of example.foo.Baz and example.bar.Baz, and that example.foo.Baz has already directly imported in this source file, adding a type annotation to a method which returns example.bar.Baz would generate an import statement for example.bar and the type added would be bar.Baz.