Wildcard Import, then Hide Particular Implicit?
Asked Answered
F

2

3

Given the following object with 2 implicits:

scala> object Foo {
     |  implicit def stringToInt(x: String) = 555
     |  implicit def stringToBoolean(x: String) = true
     | }
warning: there were two feature warnings; re-run with -feature for details
defined object Foo

I can use them:

scala> def f(x: Int) = x
f: (x: Int)Int

scala> import Foo._
import Foo._

scala> f("asdf")
res0: Int = 555

scala> def g(b: Boolean) = b
g: (b: Boolean)Boolean

scala> g("asdfasdf")
res1: Boolean = true

Then, I tried to disable the stringToInt implicit.

scala> import Foo.{stringToInt => _}
import Foo.{stringToInt=>_}

But, evidently, that did not work.

scala> f("adsfasdf")
res2: Int = 555

After wildcard importing implicits, is it possible to hide them?

Basically, I'd like to use all of Foo's implicits, minus a single one, stringToInt.

Note - of course I could simply do import Foo.stringToBoolean only, but, for my scenario, Foo has ~25 imports, and I want to use 24 of them. As a result, it's more concise to use all, and then subtract one.

Field answered 18/9, 2015 at 21:58 Comment(3)
Ahhh don't use wildcard imports. There are differing opinions on them but I believe them to be very bad style. First because of the exact problem you have here. These types of problems can be very subtle when you are working with nontrivial types. Secondly it makes your code base hard to understand without an IDE. While an IDE can be a useful tool for some, it is not a universally adopted tool and you effectively hamstring the population of devs that choose not to use one.Mita
@Mita wildcard import of implicits in Scala is pretty standard style, such as JavaConverters._. No sane person would attempt to enumerate them.Maze
And I lament this standard. JavaConverters is an easy case. You do not need to enumerate each one. You simply import the one or two you need. I understand in some cases a wildcard import is necessary for a dsl to work. Otherwise this style is bad for readability, introduces subtle bugs and seems to have limited benefits outside of very particular cases.Mita
M
3

The REPL just approximates what to import from history, and one approximation is always to use imported implicits.

In normal code, you would disable an implicit by shadowing the identifier.

Best shot is:

scala> object X { val stringToInt = 0 }
defined object X

scala> import X._
import X._

scala> f("asdf")
<console>:20: error: type mismatch;
 found   : String("asdf")
 required: Int
       f("asdf")
         ^

or

scala> implicit val stringToInt = 0
stringToInt: Int = 0

The idea is to introduce the shadowing variable into the scope of the REPL template for the current line.

Maze answered 18/9, 2015 at 23:14 Comment(1)
There's an old PR for quarantining imports in the way you want, so maybe that facility will arrive someday.Maze
T
3

There is an existing syntax to disallow a specific import. It is an extension of the syntax for renaming/aliasing an import:

import scala.collection.concurrent.{ Map => CMap } // Import concurrent Map, but alias it to "CMap", so the predef-imported "Map" isn't shadowed.

To hide an import, you can alias it to "_":

import scala.collection.mutable.{ Map, TrieMap => _ } // Import Map, but not TrieMap

Similarly, to import all of an object, except for a specific entry, use:

import Foo.{ stringToInt => _, _ }

scala> def g(b: Boolean) = b
g: (b: Boolean)Boolean

scala> g("asdfasdf")
res1: Boolean = true

scala> def f(x: Int) = x
f: (x: Int)Int

scala> f("asdf")
<console>:13: error: type mismatch;
 found   : String("asdf")
 required: Int
              f("asdf")
                ^
Twigg answered 18/9, 2015 at 23:59 Comment(3)
FTR, that wasn't the question (though apparently the OP agrees with you). Once you do the wildcard import in REPL, you're sunk unless you work around it.Maze
@Twigg - thanks for your helpful answer, +1. However, I was rash to have accepted your answer for my question. I ended up using your solution to handle my problem, but, I believe it's only fair for me to accept the answer to my question.Field
@KevinMeredith That's fine, still glad to have helped.Twigg

© 2022 - 2024 — McMap. All rights reserved.