I thought implicits in the companion object would be found. What's wrong with this?
object Elsewhere{
case class NamedInt(i: Int, name: String)
object NamedInt{
implicit class ToNamedInt(i: Int){
def named(name: String) = NamedInt(i, name)
}
}
}
object Application{
import Elsewhere.NamedInt
//Error: value named is not a member of Int
val named: NamedInt = 3.named("bob")
}
Update: I realise I can import the implicit class directly, but I thought it should compile without it since the implicit is in the companion object. E.g. this works without an extra import
object Elsewhere{
case class MyInt(i: Int)
object MyInt{
import scala.language.implicitConversions
implicit def myIntToSome(t: MyInt): Some[Int] = Some(t.i)
}
}
object Application{
import Elsewhere.MyInt
val o: Option[Int] = MyInt(1)
}
Update 2:
Jesse Eichar comments on his blog:
You are confusing implicit parameter resolution with implicit object
conversion. Implicit object conversion is potentially dangerous so
they normally have to be imported explicitly into scope.
Caveats to that is implicit object conversions defined in superclasses
and (I am pretty sure) in package objects are automatically in scope.
This would make sense to me, but then why does the MyInt example above work?
Adding one extra line fixes things (you need to also explicitly import the companion object fields):
object Application{
import Elsewhere.NamedInt
import Elsewhere.NamedInt._
// Compiles OK now :)
val named: NamedInt = 3.named("bob")
}
Related
Given a code which takes a type, takes it's known direct subclasses, filters the ones that are case classes and then takes the companion of that case class:
def firstSubclassWithCompanion[T: TypeTag]: String = {
val superclass = implicitly[TypeTag[T]].tpe.typeSymbol.asClass
val caseClass = superclass.knownDirectSubclasses.map(_.asClass).filter(_.isCaseClass).head
s"case class $caseClass has companion ${caseClass.companion}"
}
With a simple example
sealed trait With
case class WithCase() extends With
It gives the expected return
> firstSubclassWithCompanion[With]
"class WithCase has companion object WithCase"
As With trait has a WithCase subclass, which is case class that has a companion object (defined by compiler).
However, given the following example, where the subclass is defined in the companion object of the inheriting trait:
sealed trait Without
object Without {
case class WithoutCase() extends Without
}
It doesn't return the companion object
> firstSubclassWithCompanion[Without]
"class WithoutCase has companion <none>"
It works fine if it's defined in other object.
Bugs should be reported at https://github.com/scala/bug/issues
A workaround is to use caseClass.owner.typeSignature.decl(caseClass.name) instead of caseClass.companion.
Another workaround is to translate this runtime-reflection code into a macro (compile-time reflection). Since all the classes here are defined at compile time it makes sense to use a macro.
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def firstSubclassWithCompanion[T]: String = macro firstSubclassWithCompanionImpl[T]
def firstSubclassWithCompanionImpl[T: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
import c.universe._
val superclass = weakTypeOf[T].typeSymbol.asClass
val caseClass = superclass.knownDirectSubclasses.map(_.asClass).filter(_.isCaseClass).head
val res = s"case class $caseClass has companion ${caseClass.companion}"
q"$res"
}
In playframework I am trying to write the reads/writes for JSON, along with reactivemongo's BSON handlers for my case class:
import play.api.libs.json._
import reactivemongo.api.bson._
case class SomeThing[T](id: String, name: String, value: T)
object SomeThing {
implicit val stWrites = Json.writes[SomeThing]
implicit val stReads = Json.reads[SomeThing]
implicit val stHander = Macros.handler[SomeThing]
}
Because my case class as a type parameter T, I am getting this compile error currently:
class SomeThing takes type parameters
How can I solve this issue?
You need implicit polymorphic functions:
import play.api.libs.json._
import reactivemongo.api.bson._
case class SomeThing[T](id: String, name: String, value: T)
//defined as polymorphic functions
//type T in each case needs to be accompanied by some implicit evidence
implicit def stWrites[T: OWrites]: OWrites[SomeThing[T]] =
Json.writes[SomeThing[T]]
implicit def stReads[T: Reads]: Reads[SomeThing[T]] =
Json.reads[SomeThing[T]]
implicit def stHander[T: BSONDocumentHandler]: BSONDocumentHandler[SomeThing[T]] =
Macros.handler[SomeThing[T]]
stReads[String] //this works because play has an implicit StringReads available
case class OtherThing()
stReads[OtherThing] //this doesn't work we need to define a Reads[OtherThing]
implicit val otReads: Reads[OtherThing] =
Json.reads[OtherThing]
stReads[OtherThing] //now it works
Later Edit: I dropped the generic example
I suspect most are aware of the Show example to introduce type class.
I found out this blog post https://scalac.io/typeclasses-in-scala/, and was going through it easy when I stumble upon something that I do not quite understand.
I understand everything in the blog post expect when it talks about implicit categories:
From the type class full definition with syntax and object interface
trait Show[A] {
def show(a: A): String
}
object Show {
def apply[A](implicit sh: Show[A]): Show[A] = sh
//needed only if we want to support notation: show(...)
def show[A: Show](a: A) = Show[A].show(a)
implicit class ShowOps[A: Show](a: A) {
def show = Show[A].show(a)
}
//type class instances
implicit val intCanShow: Show[Int] =
int => s"int $int"
implicit val stringCanShow: Show[String] =
str => s"string $str"
}
We get the following comment:
We may encounter a need to redefine some default type class instances. With the implementation above, if all default instances were imported into scope we cannot achieve that. The compiler will have ambiguous implicits in scope and will report an error.
We may decide to move the show function and the ShowOps implicit class
to another object (let say ops) to allow users of this type class to
redefine the default instance behaviour (with Category 1 implicits,
more on categories of implicits). After such a modification, the Show
object looks like this:
object Show {
def apply[A](implicit sh: Show[A]): Show[A] = sh
object ops {
def show[A: Show](a: A) = Show[A].show(a)
implicit class ShowOps[A: Show](a: A) {
def show = Show[A].show(a)
}
}
implicit val intCanShow: Show[Int] =
int => s"int $int"
implicit val stringCanShow: Show[String] =
str => s"string $str"
}
Usage does not change, but now the user of this type class may import only:
import show.Show
import show.Show.ops._
Default implicit instances are not brought as Category 1 implicits (although they are available as Category 2 implicits), so it’s possible to define our own implicit instance where we use such type class.
What is meant by this last comment?
Implicit instances for Show[Int] and Show[String] are defined in the Show companion object, so whenever a value of type Show is used, type class instances will be available. However, they can be overridden by the user. This makes them category 2 implicits - they come from the implicit scope.
Implicits that are brought into scope by direct import, on the other hand, are category 1 implicits. They come from the local scope and they cannot be overridden. Directly importing the implicits is hence the same as defining them on the spot - both are considered category 1. If there is more than one category 1 implicit value of the same type present in local scope, compiler will complain.
What the article says is, put your implicit implementations in the companion object, but put the "machinery" in the ops. That way users of your type class can just import the machinery which allows them to do e.g. 42.show, without bringing in the type class instances as category 1 values.
Our users can then do:
import show.Show
import show.Show.ops._
// available from Show as category 2 implicit:
println(42.show) // "int 42"
as well as:
import show.Show
import show.Show.ops._
// overriding category 2 implicit with our own category 1 implicit:
implicit val myOwnIntCanShow: Show[Int] = int => s"my own $int"
println(42.show) // prints "my own 42"
But if we didn't have the ops object and we simply put everything in the Show object, then whenever our users would do import Show._ (and they would need to, in order to be able to do 42.show) they would receive all our implicits as category 1 values and wouldn't be able to override them:
import show.Show
// Assuming everything is in `Show` (no `ops`)...
import show.Show._
implicit val myOwnIntCanShow: Show[Int] = int => s"my own $int"
// this line doesn't compile because implicits were brought
// into scope as category 1 values (via import Show._)
println(42.show)
The author of this tutorial calls higher-priority implicits (from local scope) Category-1 implicits and lower-priority implicits (from implicit scope) Category-2 implicits.
Where does Scala look for implicits?
https://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html
I am trying to understand the implicit method in Scala, in the SlashSyntax.scala I defined a customed operator method:
package com.example.hello.impl
object SlashSyntax {
final class IntOps(private val intSrc: Int) {
def \(a2: Int): Int = (intSrc.toString + a2.toString).toInt
}
}
trait SlashSyntax {
import SlashSyntax._
implicit def intOps(src: Int) = new IntOps(src)
}
then in the main method I try to use the operator but it says cannot resolve symbol :
object Test {
def main(args: Array[String]): Unit = {
import com.example.hello.impl.SlashSyntax._
val s = 10 \ 2 //cannot resolve symbol \
}
}
How can I use my own operator?
The simplest solution is to make the IntOps class an implicit class. Then
you don't need the SlashSyntax trait (or you can use it for other things)
the implicit is in the right place to be imported
the pesky implicit conversion method ... warning goes away
The issue caused by incorrect import.
import com.example.hello.impl.SlashSyntax._
Problem here is that you imported all members from object SlashSyntax instead of trait SlashSyntax. This happened because scala considered com.example.hello.impl.SlashSyntax as path. All paths can be composed only from Stable members. Traits are not Stable members but objects are stable members, so scala imported members from object SlashSyntax.
You can just move your implicit method to object SlashSyntax and this will fix the issue.
Your object SlashSyntax doesn't extends trait SlashSyntax so your extension methods are not seen when you do SlashSyntax._.
Additionally you didn't do import scala.languageFeatures.implicitConversions. though you might have added -language:implicitConversions flag to scalac.
Sometimes lack of type annotation break things. Not in your case but it's good in general to these things there.
This works:
object SlashSyntax extends SlashSyntax {
final class IntOps(private val intSrc: Int) {
def \(a2: Int): Int = (intSrc.toString + a2.toString).toInt
}
}
trait SlashSyntax {
import SlashSyntax.IntOps
implicit def intOps(src: Int): IntOps = new IntOps(src)
}
I am trying to use the typeclass pattern in Scala to mark all the valid API serializable types, so that we can have compile-time safety around what we serialize. Our underlying library accepts an AnyRef which can lead to weird errors when not explicitly declaring the type before serializing it.
We allow sending out a public model, an iterable of public models, an option of public model, or a unit.
trait PublicModel
case class UserModel(name: String) extends PublicModel
sealed class SafeForPublic[-T]
implicit object PublicModelOk extends SafeForPublic[PublicModel]
implicit object IterablePublicModelOk extends SafeForPublic[Iterable[PublicModel]]
implicit object OptionPublicModelOk extends SafeForPublic[Option[PublicModel]]
implicit object UnitOk extends SafeForPublic[Unit]
This method works well for everything except methods where the parameter type is an option. This is because None is an Option[Nothing], so T = Nothing which will tell the compiler to look up an implicit object of type SafeForPublic[Nothing] and it will find both SafeForPublic[PublicModel] as well as SafeForPublic[Iterable[PublicModel]]
def boxed[T : SafeForPublic](t: Option[T]) = println("wooohoo!")
boxed(Some(None)) // works
boxed(Some(1)) // doesn't compile. Int is not a valid serializable model.
boxed(Some({})) // works
boxed(Some(UserModel("ok"))) // works
boxed(Some(Seq(UserModel("ok")))) // works
boxed(None) // doesn't compile, duplicate implicits ><
Any idea how I can trick the compiler to not find duplicate implicits for Nothing. I saw Miles Sabin had a trick using:
sealed trait NotNothing[A]{
type B
}
object NotNothing {
implicit val nothing = new NotNothing[Nothing]{ type B = Any }
implicit def notNothing[A] = new NotNothing[A]{ type B = A }
}
But I couldn't figure out how to use it. Halp?
Ok, thanks to some help from the Scala IRC channel, I figured out that LowPriority implicits was created to solve this issue.
I used this to fix it:
sealed class SafeForPublic[-T]
trait LowPriorityImplicits {
implicit object PublicModelOk extends SafeForPublic[PublicModel]
implicit object IterablePublicModelOk extends SafeForPublic[Iterable[PublicModel]]
implicit object OptionPublicModelOk extends SafeForPublic[Option[PublicModel]]
implicit object UnitOk extends SafeForPublic[Unit]
}
object Implicits extends LowPriorityImplicits {
implicit object NothingOk extends SafeForPublic[Nothing]
}
import Implicits._
def boxed[T : SafeForPublic](t: Option[T]) = println("woohoo!")
boxed(None) // compiles! \o/