To question 1, it can be useful to stash implicits in superclasses as "LowPriorityImplicits", but that doesn't seem to be the use case here.
To question 2, nested packages is the usual way to bring the implicits into scope. The spec 9.2 on "packagings" uses the magic phrase, "visible under their simple names."
But there are a few strategies for exploiting implicit scope.
I'd guess from your partial example that you want to enhance Int with a method like odd
. For this use case, supplying a missing member, you have to supply a conversion as you've done.
But there are other choices for API design. For example:
Given an API:
package goofy
object API {
def api(i: IntEx) = i.odd
}
and a client of the API in a subpackage:
package goofy.foo.bar.baz
import org.junit.Test
class UseIntExTest {
import goofy.API._
@Test def usage(): Unit = {
assert(api(3))
}
}
where you've imported the API and you get the implicit scope "for free".
The conversion is in a companion object:
package goofy
class IntEx(val i: Int) {
def even = i % 2 == 0
def odd = !even
}
object IntEx {
implicit private[goofy] def `enhanced IntEx`(i: Int): IntEx = new IntEx(i)
}
This works because IntEx
is an expected type. You can also exploit type parameters in the same way.
For completeness, to show that the conversion is constrained to subpackages:
package roofy
import org.junit.Test
class BadUsageTest {
import goofy.API._
@Test def usage(): Unit = {
//assert(api(3)) // DNC
}
}