I'm implementing a Java interface with a lot of methods with Object parameters, which in my case are really Strings containing user names:
public interface TwoFactorAuthProvider {
boolean requiresTwoFactorAuth(Object principal);
... //many more methods with the same kind of parameter
}
I'm trying to use implicit conversion to convert these to User objects in my implementation:
class TwoFactorAuthProviderImpl(userRepository: UserRepository)
extends TwoFactorAuthProvider {
def requiresTwoFactorAuth(user: User): Boolean = {
...
}
}
When I define the conversion in the companion object of my class, it is picked up just fine and my class compiles:
object TwoFactorAuthProviderImpl {
implicit def toUser(principal: Any): User = {
null //TODO: do something useful
}
}
However, to be able to do the conversion, I need access to the user repository, which the TwoFactorAuthProviderImpl instance has, but the companion object does not. I thought I could possibly use an implicit parameter to pass it:
implicit def toUser(principal: Any)(implicit repo: UserRepository): User = {
val email = principal.asInstanceOf[String]
repo.findByEmail(email)
}
But with the implicit parameter, the conversion is no longer picked up by the compiler (complaining that I'm not implementing the interface).
Is there a way to get the implicit conversion that I want, or is this outside the scope of what you can do with implicits?
This should work just fine - can you supply the exact compilation error? Not implementing what interface? It looks like you would have to declare as follows:
class TwoFactorAuthProviderImpl(implicit userRepository: UserRepository)
Here's an example for the REPL to show that implicits can have implicits; I'm using paste mode to ensure that module X is the companion object of the class X
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class X(i: Int, s: String)
object X { implicit def Int_Is_X(i: Int)(implicit s: String) = X(i, s) }
// Exiting paste mode, now interpreting.
defined class X
defined module X
scala> val i: X = 4
<console>:9: error: value X is not a member of object $iw
val i: X = 4
^
But if we add an implicit string in scope
scala> implicit val s = "Foo"
s: java.lang.String = Foo
scala> val i: X = 4
i: X = X(4,Foo)
Implicits advice
Don't go overboard with implicit conversions - I think you are going too far in this sense - the principal is implicitly a mechanism by which you can discover a user, it is not implicitly a user itself. I'd be tempted to do something like this instead:
implicit def Principal_Is_UserDiscoverable(p: String) = new {
def findUser(implicit repo: UserRepository) = repo.findUser(p)
}
Then you can do "oxbow".findUser
Thanks to Oxbow's answer, I now have it working, this is only for reference.
First of all, a value that should be passed as an implicit must itself be marked implicit:
class TwoFactorAuthProviderImpl(implicit userRepository: UserRepository) ...
Second, implicit conversions are nice and all, but a method implementation signature must still match the signature of its declaration. So this does not compile, even though there is a conversion from Any to User:
def requiresTwoFactorAuth(principal: User): Boolean = { ... }
But leaving the parameter as Any, as in the declaration, and then using it as a user works just fine:
def requiresTwoFactorAuth(principal: Any): Boolean = {
principal.getSettings().getPhoneUsedForTwoFactorAuthentication() != null
}
Also, the conversion really doesn't have to be in the companion object in this case, so in the end, I left the implicit parameters out.
The full source code:
class TwoFactorAuthProviderImpl(userRepository: UserRepository)
extends TwoFactorAuthProvider {
private implicit def toUser(principal: Any): User = {
val email = principal.asInstanceOf[String]
userRepository.findByEmail(email)
}
def requiresTwoFactorAuth(principal: Any): Boolean = {
//using principal as a User
principal.getSettings().getPhoneUsedForTwoFactorAuthentication() != null
}
...
}
Related
I'm trying to remove some of the boilerplate in an API I am writing.
Roughly speaking, my API currently looks like this:
def toEither[E <: WrapperBase](priority: Int)(implicit factory: (String, Int) => E): Either[E, T] = {
val either: Either[String, T] = generateEither()
either.left.map(s => factory(s, priority))
}
Which means that the user has to generate an implicit factory for every E used. I am looking to replace this with a macro that gives a nice compile error if the user provided type doesn't have the correct ctor parameters.
I have the following:
object GenericFactory {
def create[T](ctorParams: Any*): T = macro createMacro[T]
def createMacro[T](c: blackbox.Context)(ctorParams: c.Expr[Any]*)(implicit wtt: WeakTypeType[T]): c.Expr[T] = {
import c.universe._
c.Expr[T](q"new $wtt(..$ctorParams)")
}
}
If I provide a real type to this GenericFactory.create[String]("hey") I have no issues, but if I provide a generic type: GenericFactory.create[E]("hey") then I get the following compile error: class type required by E found.
Where have I gone wrong? Or if what I want is NOT possible, is there anything else I can do to reduce the effort for the user?
Sorry but I don't think you can make it work. The problem is that Scala (as Java) uses types erasure. It means that there is only one type for all generics kinds (possibly except for value-type specializations which is not important now). It means that the macro is expanded only once for all E rather then one time for each E specialization provided by the user. And there is no way to express a restriction that some generic type E must have a constructor with a given signature (and if there were - you wouldn't need you macro in the first place). So obviously it can not work because the compiler can't generate a constructor call for a generic type E. So what the compiler says is that for generating a constructor call it needs a real class rather than generic E.
To put it otherwise, macro is not a magic tool. Using macro is just a way to re-write a piece of code early in the compiler processing but then it will be processed by the compiler in a usual way. And what your macro does is rewrites
GenericFactory.create[E]("hey")
with something like
new E("hey")
If you just write that in your code, you'll get the same error (and probably will not be surprised).
I don't think you can avoid using your implicit factory. You probably could modify your macro to generate those implicit factories for valid types but I don't think you can improve the code further.
Update: implicit factory and macro
If you have just one place where you need one type of constructors I think the best you can do (or rather the best I can do ☺) is following:
Sidenote the whole idea comes from "Implicit macros" article
You define StringIntCtor[T] typeclass trait and a macro that would generate it:
import scala.language.experimental.macros
import scala.reflect.macros._
trait StringIntCtor[T] {
def create(s: String, i: Int): T
}
object StringIntCtor {
implicit def implicitCtor[T]: StringIntCtor[T] = macro createMacro[T]
def createMacro[T](c: blackbox.Context)(implicit wtt: c.WeakTypeTag[T]): c.Expr[StringIntCtor[T]] = {
import c.universe._
val targetTypes = List(typeOf[String], typeOf[Int])
def testCtor(ctor: MethodSymbol): Boolean = {
if (ctor.paramLists.size != 1)
false
else {
val types = ctor.paramLists(0).map(sym => sym.typeSignature)
(targetTypes.size == types.size) && targetTypes.zip(types).forall(tp => tp._1 =:= tp._2)
}
}
val ctors = wtt.tpe.decl(c.universe.TermName("<init>"))
if (!ctors.asTerm.alternatives.exists(sym => testCtor(sym.asMethod))) {
c.abort(c.enclosingPosition, s"Type ${wtt.tpe} has no constructor with signature <init>${targetTypes.mkString("(", ", ", ")")}")
}
// Note that using fully qualified names for all types except imported by default are important here
val res = c.Expr[StringIntCtor[T]](
q"""
(new so.macros.StringIntCtor[$wtt] {
override def create(s:String, i: Int): $wtt = new $wtt(s, i)
})
""")
//println(res) // log the macro
res
}
}
You use that trait as
class WrapperBase(val s: String, val i: Int)
case class WrapperChildGood(override val s: String, override val i: Int, val float: Float) extends WrapperBase(s, i) {
def this(s: String, i: Int) = this(s, i, 0f)
}
case class WrapperChildBad(override val s: String, override val i: Int, val float: Float) extends WrapperBase(s, i) {
}
object EitherHelper {
type T = String
import scala.util._
val rnd = new Random(1)
def generateEither(): Either[String, T] = {
if (rnd.nextBoolean()) {
Left("left")
}
else {
Right("right")
}
}
def toEither[E <: WrapperBase](priority: Int)(implicit factory: StringIntCtor[E]): Either[E, T] = {
val either: Either[String, T] = generateEither()
either.left.map(s => factory.create(s, priority))
}
}
So now you can do:
val x1 = EitherHelper.toEither[WrapperChildGood](1)
println(s"x1 = $x1")
val x2 = EitherHelper.toEither[WrapperChildGood](2)
println(s"x2 = $x2")
//val bad = EitherHelper.toEither[WrapperChildBad](3) // compilation error generated by c.abort
and it will print
x1 = Left(WrapperChildGood(left,1,0.0))
x2 = Right(right)
If you have many different places where you want to ensure different constructors exists, you'll need to make the macro much more complicated to generate constructor calls with arbitrary signatures passed from the outside.
I am trying to support an abstraction of an ID type for a framework. Example here:
object AmINecessary {
case class StringConverter[T](op: String => T)
implicit val toInt = new StringConverter[Int](_.toInt)
implicit val toLong = new StringConverter[Long](_.toLong)
}
class Foo[ID] {
// ID can be String, Long, or Int
import AmINecessary._
// If ID is string, return string, otherwise convert to ID
def getID(id: String)(implicit c: StringConverter[ID] = null): ID = if (c == null) id.asInstanceOf[ID] else c.op(id)
}
This is then used as:
val fooString = new Foo[String]
val fooLong = new Foo[Long]
val fooInt = new Foo[Int]
fooString.getID("asdf") // "asdf":String
fooLong.getID("1234") // 1234:Long
fooInt.getID("1234") // 1234:Int
fooInt.getID("asdf") // java.lang.NumberFormatException
This works as expected. My questions are:
using an optional implicit by defaulting it to null then branching on it feels bad. What is the scala way to accomplish that?
Is it really necessary to write implicit conversions for a string to long or int?
I think the best option would be to simply add an implicit StringConverter[String] and remove the default null value.
That way your fooString works without risking a ClassCastException for every other type.
object AmINecessary {
case class StringConverter[T](op: String => T)
implicit val toInt = new StringConverter[Int](_.toInt)
implicit val toLong = new StringConverter[Long](_.toLong)
implicit val idConverter = new StringConverter[String](identity)
}
class Foo[ID] {
import AmINecessary.StringConverter
def getID(id: String)(implicit c: StringConverter[ID]): ID = c.op(id)
}
Regarding your question 2, the type class approach is not really necessary (but note that there are no implicit conversions here). You can also do it like this:
abstract class Foo[ID] {
def getID(id: String): ID
}
class FooInt extends Foo[Int] {
def getID(id: String) = id.toInt
}
class FooLong extends Foo[Long] {
def getID(id: String) = id.toLong
}
class FooString extends Foo[String] {
def getID(id: String) = id
}
1) About implicit defaulting to null, you could just:
object Unsafe {
implicit val toT[T] = new StringConverter[T](_.asInstanceOf[T])
}
2) It doesn't seem as a good idea. First, because you're hiding asInstanceOf, which is unsafe operation (potential runtime exception). Second, the more explicit conversion is - the better.
If you expect some complex transformations - it's better to return option from your getID method:
def getId[T](id: String)(converter: Option[StringConverter] = None) = converter.map(_.op(id))
However, default parameters aren't the best approach either. I'd stick with compile-time error requiring user to either write own converter or explicitly do an asInstanceOf, in general.
In your concrete case asInstanceOf doesn't make much sense as the only type it would work for is String, like getId[String], so what's the point of calling getId then?
I'm trying to access an implicit parameter for a generic type. Scala is able to find the implicit just fine in the straightforward case by calling a method with an explicit generic type, such as with printGenericType[Person] below.
However, if I create a TypeTag[Person] and pass it to printGenericTypeGivenTypeTag, Scala is unable to find the implicit parameter.
case class Person(name: String)
case class Animal(age: Int)
implicit val p = Person("cory")
implicit val a = Animal(2)
def main(args: Array[String]): Unit = {
// Can find the implicit Person, prints "Hello Person(cory)"
printGenericType[Person]
// Can find the implicit Animal, prints "Hello Animal(2)"
printGenericType[Animal]
// See comment below
printNamedType("Person")
printNamedType("Animal")
}
def printGenericType[T](implicit t: T) = {
println(s"Hello $t")
}
def printGenericTypeGivenTypeTag[T](typeTag: TypeTag[T])(implicit t: T) = {
println(s"Hello $t")
}
def printNamedType[T](name: String) = {
val typetag: TypeTag[T] = getTypeTag[T](name)
// Cannot find the implicit of type T, compiler error
printGenericTypeGivenTypeTag(typetag)
}
def getTypeTag[T](name:String): TypeTag[T] = ... //Implementation irrelevant
If I understand correctly, Scala locates implicit parameters at compile time, so it makes sense that it can't find an implicit parameter for the generic type T at compile time.
However, I know that an implicit instance of T does exist. Is it possible to rewrite printGenericTypeGivenTypeTag in such a way as to find the implicit value for T? At runtime, the method has access to the actual type of T, so it seems it should be able to locate an implicit parameter of the same type that is in scope.
For the curious, the reasoning behind this is to avoid this:
name match {
case "Person" => printGenericType[Person]
case "Animal" => printGenericType[Animal]
}
To answer the question
You're not really wanting to pass the T implicitly, but rather the TypeTag, and not the T. Here's what I mean, and you're probably better off with an implicit value class.
implicit class GenericPrinter[T](val obj: T) extends AnyVal {
def printGenericType()(implicit tag: TypeTag[T]) = {
// do stuff with the tag
Console.println("Hello $obj")
}
}
val x: Person = Person(...)
x.printGenericType
Now solving the real problem
If you are trying to print case classes, I'd probably go down the implicit macro route for added convenience. It's really trivial to write up a macro that does this for us, e.g output a debug string based on all the constructor params of an arbitrary case class.
trait DeepPrinter[T <: Product with Serializable] {
/**
* Prints a deeply nested debug string for a given case class.
* This uses implicit macros to materialise the printer type class.
* In English, when we request for an implicit printer: DeepPrinter[T],
* the pre-defined compile time macro will generate this method for us
* based on the fields of the given case class.
*
* #param sep A separator to use to delimit the rows in a case class.
* #return A fully traced debug string so we can see how a case class looks like.
*/
def debugString(sep: String = "\n"): String
}
object DeepPrinter {
implicit def deepPrinter[T <: Product with Serializable] = macro DeepPrinterImpl.deepPrinterImpl[T]
}
And the macro is pretty trivial, looks kind of like this.
import language.experimental.macros
import scala.reflect.macros.blackbox
#macrocompat.bundle
class DeepPrinterImpl(val c: blackbox.Context) {
import c.universe._
object CaseField {
def unapply(symbol: TermSymbol): Option[(Name, Type)] = {
if (symbol.isVal && symbol.isCaseAccessor) {
Some(symbol.name -> symbol.typeSignature)
} else {
None
}
}
}
def fields(tpe: Type): Iterable[(Name, Type)] = {
tpe.decls.collect { case CaseField(nm, tpeSn) => nm -> tpeSn }
}
def materialize[T : c.WeakTypeTag]: c.Expr[DeepPrinter[T]] = {
val tpe = weakTypeOf[T]
val (names, types) = fields(tpe).unzip
// change the package name to the correct one here!
val tree = q"""
new com.bla.bla.DeepPrinter[$tpe] {
def debugString(sep: String = "\n") = Seq(..$names).mkString(sep)
}
"""
c.Expr[DeepPrinter[T]](tree)
}
}
The type class pattern in Scala involves defining a trait such as:
trait Show[T] {
def show(obj: T): String
}
Then you can define instantiations of this type class as such:
object Show {
implicit val string = new Show[String] {
def show(obj: String): String = obj
}
implicit object BooleanShow extends Show[Boolean] {
def show(obj: Boolean): String = obj.toString
}
}
The advantage of defining these instantiations for basic types in the companion object is that they are automatically in scope whenever the type class is concerned (roughly).
Functionally it would appear defining the instantiation as an implicit val or an implicit object does not change much.
Is there a difference? Is one way better than the other?
There is actually more than the type names between val and object.
You know, object in Scala is something like a singleton in Java.
Maybe you thought that both string and BooleanShow are in an object not a class so they have no difference, but that's not true.
They are val and object no matter what.
Try this in Scala REPL.
trait Show[T] {
def show(obj: T): String
}
object Show {
println("!! Show created")
implicit val string = new Show[String] {
println("!! string created")
def show(obj: String): String = obj
}
implicit object BooleanShow extends Show[Boolean] {
println("!!BooleanShow created")
def show(obj: Boolean): String = obj.toString
}
}
If only the definition is done, then no printlns are executed afterwards, since Show is a singleton in effect. It's not created yet.
Next, execute Show in Scala REPL.
scala> Show
!! Show created
!! string created
res0: Show.type = Show$#35afff3b
You see, printlns in Show and Show.string were called, but the one in Show.BooleanShow was not.
You can execute Show.BooleanShow next in Scala REPL.
scala> Show.BooleanShow
!!BooleanShow created
res1: Show.BooleanShow.type = Show$BooleanShow$#18e419c5
Show.BooleanShow was initialized at last. It is a singleton, so it is lazy.
Basically, your question is the same as val and object inside a scala class? except that your val and object are defined in an object, but the linked question tries to find differences val and object defined in a class and the method in val uses reflection (but yours uses overriding, so no reflection is involved). implicit basically does not make difference in what they are.
I think you already know the difference between class and object. Further information can be found in the linked question.
Since they say always to use explicit types for implicits, prefer val over object.
Compare Why can't Scala find my typeclass instance defined implicitly in the companion object, when the typeclass is not in a dedicated source file? where it makes a difference.
Make it lazy if necessary.
Elaboration:
scala> trait T
defined trait T
scala> object X { implicitly[T] ; object O extends T }
<console>:8: error: could not find implicit value for parameter e: T
object X { implicitly[T] ; object O extends T }
^
scala> object X { implicitly[T] ; implicit object O extends T }
<console>:8: error: could not find implicit value for parameter e: T
object X { implicitly[T] ; implicit object O extends T }
^
scala> object X { implicitly[O.type] ; implicit object O extends T }
defined object X
scala> object X { implicitly[T] ; implicit object O extends T ; implicit def y = O }
<console>:8: error: could not find implicit value for parameter e: T
object X { implicitly[T] ; implicit object O extends T ; implicit def y = O }
^
scala> object X { implicitly[T] ; implicit object O extends T ; implicit def y: T = O }
defined object X
The inferred type of O is the singleton type O.type.
With val x = new X { } you are creating an anonymous subclass of X, whereas with object x extends X you create a "proper" subclass. I would think that the overhead of an object is minimal, and as #applicius points out, it has proper name. Therefore I suggest to go for the object in this case.
I have a class that takes an implicit parameter which is used by functions called inside class methods. I want to be able to either override that implicit parameter, or alternatively, have the implicit argument be copied from its source. As an example:
def someMethod()(implicit p: List[Int]) {
// uses p
}
class A()(implicit x: List[Int]) {
implicit val other = List(3) // doesn't compile
def go() { // don't want to put implicit inside here since subclasses that override go() have to duplicate that
someMethod()
}
}
The behavior I want is that someMethod() gets an implicit parameter that is some changed version of x, which was the class's implicit parameter. I want to be able to either mutate x without changing it for whatever passed it into A's constructor, or otherwise override it to a new value of my choosing. Both approaches don't seem to work. That is, it doesn't copy the list in the former case, and the compiler finds an ambiguous implicit value for the latter case. Is there a way to do this?
I realize that I can redefine the implicit value within go(), but this is not a good choice in my case because this class is subclassed numerous times, and I'd like to handle this implicit change in the base class only. So it doesn't necessarily need to go in the constructor, but it must be in a method other than go().
Introduce another wrapper type, simply to disambiguate:
// badly named, choose something domain-specific
case class ListHolder(theList: List[Int])
def someMethod()(implicit holder: ListHolder) {
val xs = holder.theList
// uses xs ...
}
class A()(implicit xs: List[Int]) {
implicit val other = ListHolder(42 :: xs) // compiles
def go() {
// xs is never considered for the implicit param to someMethod()
// because it's now the wrong type
}
}
This also makes the code more self-documenting, as it becomes blindingly obvious that the two implicits are not one and the same.
If you want to have zillions of implicits floating around that don't collide with each other, you can create a wrapper class that you can tag with marker traits for implicit usage. There are a variety of syntaxes you could use; here's one example:
object Example {
class Implication[A,B](val value: A) {
def apply[C](c: C) = new Implication[C,B](c)
}
object Implication {
def mark[B] = new Implication[Unit,B](())
implicit def implication_to_value[A,B](i: Implication[A,B]) = i.value
}
trait One {}
trait Two {}
implicit val x = Implication.mark[One]("Hello")
implicit val y = Implication.mark[Two]("Hi")
def testOne(implicit s: Implication[String,One]) = println(s: String)
def testTwo(implicit s: Implication[String,Two]) = println(s: String)
def testThree(s: String) = println("String is " + s)
def main(args: Array[String]) {
testOne
testTwo
testThree(x)
testThree(y)
}
}
Which works as you would hope:
scala> Example.main(Array())
Hello
Hi
String is Hello
String is Hi
Since you have to use a wrapper object, it's not super-efficient, but it can be very effective. (Or very confusing, given how much happens implicitly.)
This modification compiles. I changed x into a var:
class A()(implicit var x: List[Int]) {
def someMethod()(implicit p: List[Int]) {
// uses p
}
x = List(3)
def go() { // don't want to put implicit inside here since subclasses that override go() have to duplicate that
someMethod()
}
}