Wildcard imports considered harmful

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

If you donā€™t know where it was from at all, not even which library, then you downgrade (by switching to an earlier branch that compiled) and

  1. If you have an IDE, ask the IDE
  2. if not, drop : Nothing on an instance of it and recompile

Now you know where itā€™s from and you can go search the API to try to find where it went.

If you do know where it was from, just go search the new API docs like youā€™d have had to if it said error: object Thing is not a member of package boromir.

This elaborate scenario has a simple solution.

Personally, Iā€™ve run into ā€œhereā€™s sample code but it doesnā€™t work because they elided the imports because theyā€™re too longā€ as an error way more than ā€œthis worked great, but after an upgrade things went missing and you canā€™t find where they used to come from and that is critical to solving the problemā€.

Anyway, anyone who wants to is already free to not import everything from each member of the Fellowship of the Ring. If youā€™re just after Sting, a frying pan, and a horn, Scala certainly doesnā€™t stop you from calling them out specifically.

4 Likes

Seriously: I believe that the majority of Scala files I have worked in (11 years, 7 of them full-time) have involved at least one wildcard import. Thatā€™s not the kind of specialized feature that is well-suited to a language feature flagā€¦

4 Likes

When macros are in the mix, wildcard imports canā€™t be reliably expanded at all by tooling.

1 Like

The idea is to take advantage of the shift to Dotty to introduce this breaking change. It is mainly in reaction to implied/delegate/given imports, which also introduce a breaking change. A new proposal could be to require givens to be ā€œnon-wildcardly importedā€ : assume there is a field myimplicit in package foo. Then,

import foo._
import given foo._

should be written instead as:

import foo.{_, myimplicit}

What do you think ?

I think itā€™s a really good way to raise the effort of migration enough to keep people on Scala 2. At least based on what I understand from whatā€™s been described here, itā€™d be a deal-breaker for me.

4 Likes

To be fair, the idea that advancing a major version is now the opportunity to change everything did not originate from @rjolly. My understanding is that we should all stop worrying and love ScalaFix.

I get that wildcard imports are far too popular to be killed. But if this conversation will convince a few people to use them less, it was worth it talking about it.

It was implied earlier that implicits may not have a name, so they cannot be imported by name, and maybe that means we need to always import them via wildcards. That sounds pretty terrible to me - what if there are conflicts among some of the imported unnamed implicits. There must be a way to refer to them individually in imports. My understanding is that they do not need a name, because we can refer to them by the name of their type. In that case, we need a way to import an implicit by naming their type. Maybe by putting the type name in square brackets? Like:

**import x.y.z.{Thing, [NiceType]} **

// imports x.y.x.Thing and the implicit instance in x.y.z that has type NiceType.

2 Likes

By-type imports are already implemented, see https://dotty.epfl.ch/docs/reference/contextual/import-delegate.html . I thought it was overly complicated, but maybe it is the way to go. The part that bothers me is when used in normal imports (non implied/delegate/given):

import foo.{_: MyType}

It makes sense for fields and objects, but what about methods ? And types ? And classes ?

If you prefer not using IDE, just do not use it. If you prefer not using wildcard, just do not use it.

I donā€™t see why we need to take this away from users and enforce someā€™s preference to everyone.

4 Likes