I defined implicit conversions in an object
. Let's call the object Implicits
and there is one implicit conversion in it.
package com.gmail.naetmul.stackoverflow.app
object Implicits {
implicit def int_to_intEx(x: Int): IntEx = IntEx(x)
}
This object is in some package. I want to use this implicit conversion in every code in the package com.gmail.naetmul.stackoverflow.app
and all of its sub-packages like com.gmail.naetmul.stackoverflow.app.something.anything.everything
.
So I made the package object of com.gmail.naetmul.stackoverflow.app
.
package com.gmail.naetmul.stackoverflow
package object app {
import com.gmail.naetmul.stackoverflow.app.Implicits._
}
But it didn't work outside of the exact package object.
So I changed the object Implicits
to trait
and let the package object extend it.
package com.gmail.naetmul.stackoverflow.app
trait Implicits {
implicit def int_to_intEx(x: Int): IntEx = IntEx(x)
}
package com.gmail.naetmul.stackoverflow
import com.gmail.naetmul.stackoverflow.app.Implicits
package object app extends Implicits {
// some code
}
The implicit conversion worked in the package com.gmail.naetmul.stackoverflow.app
. However, it either worked or did not work in the sub-package.
For example)
File A.scala
package com.gmail.naetmul.stackoverflow.app.database
class A {
// Here, the implicit conversion did NOT work.
}
File B.scala
package com.gmail.naetmul.stackoverflow.app
package database
class B {
// Here, the implicit conversion DID work.
}
So the question is:
Should I use trait
instead of object
in this case (using with the package object, but defined outside)?
Is there another way to use the implicit conversions in subpackages?
I mean, import only once, and use them everywhere. The way that worked in B.scala
seems fine, but the Eclipse's default package statement is like A.scala
, so I have to change them manually.
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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With