Wildcard imports considered harmful

There’s the rub: if you’re importing implicit instances, enumerating each one by name is a real pain in the neck. This’ll be more of a problem in Dotty, where they might not have a name.

1 Like

Yes. Unless your IDE can give you a hand. In addition, it would be done once and for all, removing the burden for the compiler to search for these elements over and over again.

Some people prefer not to have language features that make an IDE a requirement for getting anything done.

Also, even if the IDE helps, the burden of writing, reading, and maintaining code is increased because of all the busywork surrounding semi-manual management of individual imports.

6 Likes

If you are using wildcard imports two or more times within the same scope, how would you even find where something got imported from without IDE?

Why would you care unless the compiler flags an error, at which point the compiler would tell you?

2 Likes

Of course you can not.
But take into consideration that you also cannot do any other cross navigation without IDE.

 val x = getObject
  x.doSomeThing() // how would you even find where the method is declared?

IMHO: Import itself can be considered as boilerplate code in some high level areas
So wildcard imports can be just less evil.

I agree that for anonymous instances, we still have to come up with something. However, if I understand correctly, this is only a problem for orphan instances, which we could require to have a name.

While it’s more of an issue for anonymous instances, it’s still an issue for named instances. Who really wants to maintain 20 lines of imports from the same file when a wildcard would provide the compiler the same information?

It’s tedious, and distracts from actually getting work done.

1 Like

Because it helps understanding the code ?

How would you understand a piece of code without understanding what those things in it are?

I haven’t found a case where this:

import cats.instances.vector.{
  catsStdInstancesForVector,
  catsStdShowForVector,
  catsKernelStdOrderForVector,
  catsKernelStdMonoidForVector,
  catsKernelStdPartialOrderForVector,
  catsKernelStdHashForVector,
  catsKernelStdEqForVector
}

Provides more useful information than this:

import cats.instances.vector._

Fun side note: the more verbose version is actually harder to use, because it flattens the implicit scope so you can’t take advantage of the nicely layered priorities setup by the library maintainers.

4 Likes

How does having a list of names help you understand it?

Types are far more informative, and you get those without needing the imports: at the use site with an IDE, or in error messages from the compiler. Even with no editor support at all, it takes a few seconds to drop a : Nothing on any variable you please and the compiler will helpfully yell the type back at you.

3 Likes

I find wild card imports very useful. They may well be a problem when using large numbers of independently written libraries, but that is not the only way of writing Scala code. I try to think quite carefully about naming in the packages that I’m wild card importing, so naming conflicts very rarely occur and are removed, when they do. From this perspective it is selective imports from a package or even an object that are code smells.

2 Likes

If I have the full name (x.y.z.Thing), I can look it up in the ScalaDoc, or at least know which library Thing came from.

To recompile one file, I would have to have all dependencies in place. Basically, tell my build tool to compile only one file. And somehow also tell my build tool that all files depending on the changed file are not out-dated, because I’m going to cancel the change. Not sure which build tool supports that.

All of this assumes, of course, that my project is in a buildable state to begin with.

Let’s say I’ve been using Thing and after upgrading dependencies, it no longer is where it was. If I had imported it using import x.y.z.Thing, I could easily see that x.y.z.Thing no longer exists. If, however, I used import x.y.z._, all I would get is that Thing is unknown, with no hint where it used to be.

Also, consider:

import frodo._

import samwise._
import peregrin._

import meriadoc._

import gandalf._

import aragon._

import boromir._

import gimli._
import legolas._

val usefulThing = new Thing

What is the full name of Thing here? Could be just Thing. Or frodo.Thing or samwise.Thing or peregrin.Thing, etc. Or frodo.samwise.Thing or frodo.peregrin.Thing or frodo.samwise.peregrin.Thing. I’m counting 512 possibilities what the full name might be.

1 Like

That makes at least overuse of wildcard imports harmful.

So use jump-to-definition in IJ, or whatever ENSIME offers, or write val usefulThing: Nothing = new Thing. This is not dissimilar to Java wildcard imports, other than that they can be relative – the “problem” still exists, although there are fewer possible resolutions.

That would be an excellent feature.

Is this thread a proposal to remove wildcard imports, or are we just bellyaching over a feature anyone’s free to not use?

3 Likes

The proposal is at least to put it behind a language feature flag. This is especially important in Scala (compared to Java) because of implicits. How do we jump-to-definition with something that is not even visible ?

To clarify, would you be proposing blocking this syntax as well?

val x = Foo()
import x._

I had not thought of it. Do you have a case where it would be a problem ? First that comes to mind is that it would not be simple for IDEs to auto-generate imports anywhere but at the top-level.

One place which this is used that comes to mind is if you want to limit the scope of implicits like:

import org.json4s.dsl._

Which, IIRC, is importing the members of an object, which is equivalent to the above.

Oh, and Akka’s graph building DSL also relies on a similar mechanism.

Clarifying note on the motivation for this line of questioning: I’m deeply opposed to this proposal, but I’d also like to avoid ripping into a strawman, so I want to make sure I understand the details of what you’re proposing

1 Like