I have the following code, that I can not figure out, what the difference:
implicit def boxPrintable[A](implicit p: Printable[A]) =
p.contramap[Box[A]](_.value)
implicit val stringPrintable: Printable[String] =
new Printable[String] {
def format(value: String): String =
"Foo " |+| value |+| " Too"
}
Both are the implementation for types. The question is, when to use def and when to use val?
The whole code:
package com.sweetsoft
import cats.instances.string._
import cats.syntax.semigroup._
import cats.Contravariant
import cats.Show
import cats.instances.string._
final case class Box[A](value: A)
trait Printable[A] {
self =>
def format(value: A): String
def contramap[B](func: B => A): Printable[B] =
new Printable[B] {
override def format(value: B): String = self.format(func(value))
}
}
object Main {
val showString = Show[String]
implicit def boxPrintable[A](implicit p: Printable[A]) =
p.contramap[Box[A]](_.value)
implicit val stringPrintable: Printable[String] =
new Printable[String] {
def format(value: String): String =
"Foo " |+| value |+| " Too"
}
implicit val booleanPrintable: Printable[Boolean] =
new Printable[Boolean] {
def format(value: Boolean): String =
if (value) "yes" else "no"
}
def main(args: Array[String]): Unit = {
println(format("Hello"))
//println(format(Box("hello world")))
}
def format[A](value: A)(implicit p: Printable[A]): String =
p.format(value)
}
Your boxPrintable takes a type parameter A and a value argument of type Printable[A], so it must be a def.
String is one specific type, so stringPrintable takes no parameters at all, it's just a constant, so you can define it to be a val.
Nothing more to it.
def is evaluated on each request.
val is evaluated when the class is created.
In your example you need a def as soon it has parameters, which are not possible with vals.
Related
Consider the following setup:
trait Foo[A]
object Foo extends Priority2
trait Priority0 {
implicit def foo1: Foo[Int] = new Foo[Int] {}
}
trait Priority1 extends Priority0 {
implicit def foo2: Foo[Boolean] = new Foo[Boolean] {}
}
trait Priority2 extends Priority1 {
implicit def foo3: Foo[Double] = new Foo[Double] {}
}
Now, in a REPL (having loaded the above code up), I can do the following:
scala> def implicitlyFoo[A](implicit foo: Foo[A]) = foo
implicitlyFoo: [A](implicit foo: Foo[A])Foo[A]
scala> implicitlyFoo
res1: Foo[Double] = Priority2$$anon$3#79703b86
Is there a way to encode with some typelevel magic that I want to skip over the instances with A =:= Double, but still let type inference figure out what A is?
I do not want to shadow foo3. This is an MVCE: in my real case, foo3 is a def with other implicit arguments (and may play an indirect role in deriving other Foo's).
I've tried =:!= from shapeless but to no avail:
scala> import shapeless._
import shapeless._
scala> def implicitlyFoo2[A](implicit foo: Foo[A], ev: A =:!= Double) = foo
implicitlyFoo2: [A](implicit foo: Foo[A], implicit ev: A =:!= Double)Foo[A]
scala> implicitlyFoo2
<console>:16: error: ambiguous implicit values:
both method neqAmbig1 in package shapeless of type [A]=> A =:!= A
and method neqAmbig2 in package shapeless of type [A]=> A =:!= A
match expected type Double =:!= Double
implicitlyFoo2
^
Dirty hack is to downcast macro context to its implemenation and use compiler internals.
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
trait Foo[A] {
def say: String
}
trait Priority0 {
implicit def foo1: Foo[Int] = new Foo[Int] {
override def say: String = "int"
}
}
trait Priority1 extends Priority0 {
implicit def foo2: Foo[Boolean] = new Foo[Boolean] {
override def say: String = "bool"
}
}
trait Priority2 extends Priority1 {
implicit def foo3: Foo[Double] = new Foo[Double] {
override def say: String = "double"
}
}
object Foo extends Priority2
def materializeSecondFoo[A]: Foo[A] = macro impl
def impl(c: whitebox.Context): c.Tree = {
import c.universe._
val context = c.asInstanceOf[reflect.macros.runtime.Context]
val global: context.universe.type = context.universe
val analyzer: global.analyzer.type = global.analyzer
var infos = List[analyzer.ImplicitInfo]()
new analyzer.ImplicitSearch(
tree = EmptyTree.asInstanceOf[global.Tree],
pt = typeOf[Foo[_]].asInstanceOf[global.Type],
isView = false,
context0 = global.typer.context.makeImplicit(reportAmbiguousErrors = false),
pos0 = c.enclosingPosition.asInstanceOf[global.Position]
) {
override def searchImplicit(
implicitInfoss: List[List[analyzer.ImplicitInfo]],
isLocalToCallsite: Boolean
): analyzer.SearchResult = {
val implicitInfos = implicitInfoss.flatten
if (implicitInfos.nonEmpty) {
infos = implicitInfos
}
super.searchImplicit(implicitInfoss, isLocalToCallsite)
}
}.bestImplicit
val secondBest = infos.tail.head
global.gen.mkAttributedRef(secondBest.pre, secondBest.sym).asInstanceOf[Tree]
}
materializeSecondFoo.say // bool
Tested in 2.12.8. Motivated by shapeless.Cached.
In 2.13.0 materializeSecondFoo.say should be replaced with
val m = materializeSecondFoo
m.say
The latter is still working in 2.13.10.
Scala 3 implementation:
import scala.quoted.{Quotes, Type, Expr, quotes}
import dotty.tools.dotc.typer.{Implicits => dottyImplicits}
transparent inline def materializeSecondFoo: Foo[_] = ${impl}
def impl(using Quotes): Expr[Foo[_]] = {
import quotes.reflect.*
given c: dotty.tools.dotc.core.Contexts.Context =
quotes.asInstanceOf[scala.quoted.runtime.impl.QuotesImpl].ctx
val typer = c.typer
val search = new typer.ImplicitSearch(
TypeRepr.of[Foo[_]].asInstanceOf[dotty.tools.dotc.core.Types.Type],
dotty.tools.dotc.ast.tpd.EmptyTree,
Position.ofMacroExpansion.asInstanceOf[dotty.tools.dotc.util.SourcePosition].span
)
def eligible(contextual: Boolean): List[dottyImplicits.Candidate] =
if contextual then
if c.gadt.isNarrowing then
dotty.tools.dotc.core.Contexts.withoutMode(dotty.tools.dotc.core.Mode.ImplicitsEnabled) {
c.implicits.uncachedEligible(search.wildProto)
}
else c.implicits.eligible(search.wildProto)
else search.implicitScope(search.wildProto).eligible
def implicits(contextual: Boolean): List[dottyImplicits.SearchResult] =
eligible(contextual).map(search.tryImplicit(_, contextual))
val contextualImplicits = implicits(true)
val nonContextualImplicits = implicits(false)
val contextualSymbols = contextualImplicits.map(_.tree.symbol)
val filteredNonContextual = nonContextualImplicits.filterNot(sr => contextualSymbols.contains(sr.tree.symbol))
val successes = (contextualImplicits ++ filteredNonContextual).collect {
case success: dottyImplicits.SearchSuccess => success.tree.asInstanceOf[ImplicitSearchSuccess].tree
}
successes.tail.head.asExprOf[Foo[_]]
}
materializeSecondFoo.say // bool
val foo = materializeSecondFoo
foo: Foo[Boolean] // compiles
Scala 3.2.0.
Suppose I have a case class below
case class SomeCaseClass[M] private (
value: String
)
and in another file, I have the following trait and object.
trait SomeTrait[A] {
def get(oldId: String): A
:
}
object SomeObject {
private[this] def init[A](): SomeTrait[A] = new SomeTrait[A] {
def get(oldId: String): A = id(oldId)
:
}
val aaa: SomeTrait[String] = init[String]()
val bbb: SomeTrait[SomeCaseClass[String]] = init[SomeCaseClass[String]]()
}
How should I modify the code so that restrict the init method only to being used with SomeCaseClass[_] type and not with any types like String as above?
Ideally with some modification to the code, the line val aaa: SomeTrait[String] = init[String]() should cause compilation error.
This is what I came up with:
case class SomeCaseClass[M] private (
value: String
)
trait SomeTrait[A] {
def get(oldId: String): A
}
private[this] def init[A <: SomeCaseClass[_]](): SomeTrait[A] = new SomeTrait[A] {
def get(oldId: String): A = ???
}
val aaa: SomeTrait[String] = init[String]() // Will fail
val bbb: SomeTrait[SomeCaseClass[String]] = init[SomeCaseClass[String]]()
It fails with
ScalaFiddle.scala:16: error: type arguments [String] do not conform to method init's type parameter bounds [A <: ScalaFiddle.this.SomeCaseClass[_$1] forSome { type _$1 }]
You can check this scalafiddle.
I do not know if this is the best approach, but init[A <: SomeCaseClass[_]] is adding a type bound to A, and forcing A to be a Subclass of SomeCaseClass. I would love to know if there is a better way though.
You can force a type parameter to be equal to some type B by using an implicit parameter:
def foo[A](implicit e: A =:= B): …
Also see this question.
To add some more value to this answer.
Following code shows how to use the implicit parameter e: A =:= String to convert an A to a String.
def bar(b: String): Unit = println(b)
def foo[A](a: A)(implicit e: A =:= String): Unit = {
bar(e(a))
}
foo("hi") //compiles
foo(5) //error: Cannot prove that scala.this.Int =:= String.
Answer to problem the OP has
This problem is much simpler: Make the method parametric only in the parameter A of SomeCaseClass[A], instead of using the whole type SomeCaseClass[A] as a type parameter:
private[this] def init[A](): SomeTrait[SomeCaseClass[A]] = new
SomeTrait[SomeCaseClass[A]] {
def get(oldId: String): SomeCaseClass[A] = ???
}
This is based on the answer above:
case class SomeCaseClass[M] private (
value: String
)
trait SomeTrait[A] {
def get(oldId: String): SomeCaseClass[A]
}
private[this] def init[A](): SomeTrait[A] = new SomeTrait[A] {
def get(oldId: String): SomeCaseClass[A] = ???
}
val aaa: SomeTrait[String] = init[String]()
(https://scalafiddle.io/sf/KuXZc0h/3)
This doesn't allow other types than SomeCaseClass to be used with SomeTrait.
I trying to understand imap functor and have the following code:
trait Codec[A] {
def encode(value: A): String
def decode(value: String): A
def imap[B](dec: A => B, enc: B => A): Codec[B] = {
val self = this
new Codec[B] {
override def encode(value: B): String =
self.encode(enc(value))
override def decode(value: String): B =
dec(self.decode(value))
}
}
}
object Codec {
implicit val stringCodec: Codec[String] =
new Codec[String] {
override def encode(value: String): String = value
override def decode(value: String): String = value
}
implicit val intCodec: Codec[Int] =
stringCodec.imap(_.toInt, _.toString)
implicit val booleanCodec: Codec[Boolean] =
stringCodec.imap(_.toBoolean, _.toString)
implicit val doubleCodec: Codec[Double] =
stringCodec.imap(_.toDouble, _.toString)
def encode[A](value: A)(implicit c: Codec[A]): String =
c.encode(value)
def decode[A](value: String)(implicit c: Codec[A]): A =
c.decode(value)
}
Converting for example from double to string it works:
def main(args: Array[String]): Unit = {
println(Codec.encode(34.343))
}
but from String to double:
def main(args: Array[String]): Unit = {
println(Codec.decode("34.343"))
}
I've got the error message:
Error:(44, 24) ambiguous implicit values:
both value stringCodec in object Codec of type => io.khinkali.Codec[String]
and value intCodec in object Codec of type => io.khinkali.Codec[Int]
match expected type io.khinkali.Codec[A]
println(Codec.decode("34.343"))
Error:(44, 24) could not find implicit value for parameter c: io.khinkali.Codec[A]
println(Codec.decode("34.343"))
Error:(44, 24) not enough arguments for method decode: (implicit c: io.khinkali.Codec[A])A.
Unspecified value parameter c.
println(Codec.decode("34.343"))
What do I forget?
You forgot to specify type for decode operation:
Codec.decode[Double]("34.343")
You have two implicit codecs in the scope: Codec[Int] and Codec[Double]. How does compiler know which one you want to use?
You have multiple options (implicits) for the decode function. If you specify the type parameter, then the compiler will be able to choose the right one: Codec.decode[Double]("34.343").
I am currently trying to write a method that takes a JSON (what API does not matter here) and validates it. I want the method to look something like this:
def validateJson(json, expectedType: Map[String, Type(?)], allowedVals: Map[String, Seq[expectedType(key)]]): Boolean
The problem is: I do have a method jsonfield.validate[expectedType] but I do not know how to pass an unknown number of useable type parameters associated with strings to a method.
I'd gladly use some runtime reflection if that is possible here, or any advanced feature necessary to make this work easily. Any suggestions appreciated.
PS: I am using Play Framework 2.6.3
Edit:
I am trying to use the passed types like this
val allowed = allowedVals(field) // a Set
// if field contents contained in allowed value set...
if( allowed(field.validate[expectedType(field)].get) ) foo
Maybe you can use varargs in runtime or abstract over arity in compile time or just use an HList:
def foo[L <: HList](l: L) = ???
trait A
trait B
trait C
val a: A = new A {}
val b: B = new B {}
val c: C = new C {}
foo[A :: B :: C :: HNil](a :: b :: c :: HNil)
Sounds like you're looking for dependent type/dependent function/polymorphic function:
import shapeless.Poly1
import shapeless.syntax.singleton._
object expectedTypeAndValue extends Poly1 {
implicit val aCase: Case.Aux["a", Int] = at["a"](_ => 1)
implicit val bCase: Case.Aux["b", Long] = at["b"](_ => 2L)
implicit val cCase: Case.Aux["c", Double] = at["c"](_ => 3.0)
}
def validateJson(json: Json): Boolean = {
val x: Long = expectedTypeAndValue["b"]("b".narrow)
???
}
in Typelevel Scala or
import shapeless.{Poly1, Witness}
import shapeless.syntax.singleton._
object expectedTypeAndValue extends Poly1 {
implicit val aCase: Case.Aux[Witness.`"a"`.T, Int] = at[Witness.`"a"`.T](_ => 1)
implicit val bCase: Case.Aux[Witness.`"b"`.T, Long] = at[Witness.`"b"`.T](_ => 2L)
implicit val cCase: Case.Aux[Witness.`"c"`.T, Double] = at[Witness.`"c"`.T](_ => 3.0)
}
def validateJson(json: Json): Boolean = {
val x: Long = expectedTypeAndValue[Witness.`"b"`.T]("b".narrow)
???
}
in Lightbend Scala (ordinary Scala).
You can create also custom type class:
trait ExpectedTypeAndVals[S <: String] {
type Out
def apply(s: S): Set[Out]
}
object ExpectedTypeAndVals {
type Aux[S <: String, Out0] = ExpectedTypeAndVals[S] {type Out = Out0}
implicit def mkExpectedTypeAndVals[S <: String]: ExpectedTypeAndVals.Aux[S, ???] =
new ExpectedTypeAndVals[S] {
override type Out = ???
override def apply(s: S): Set[Out] = ???
}
}
def allowed[S <: String, Out](json: Json)(implicit
typeAndVals: ExpectedTypeAndVals.Aux[S, Out]
): Boolean = {
val str: S = ???
val set: Set[Out] = typeAndVals(str)
???
}
if(allowed(json)) {
???
}
There is a good way to make the line 1.print works without defining an implicit intPrintable?
I would like to say to the compiler to use the stringPrintable implementation also for Int type without provide a new implicit Printable[Int], the idea is to say to compiler that Int can be viewed as String
Here the example:
trait Printable[T]{
def print(in: T): String
}
object Printable{
def apply[T](f: T => String): Printable[T] = new Printable[T] {
def print(in: T): String = f(in)
}
}
implicit class PrintableOps[T](v: T)(implicit printable: Printable[T]) {
def print: String = printable.print(v)
}
implicit val stringPrintable: Printable[String] = Printable((in: String) => s"print $in")
implicit def intToString(i: Int): String = i.toString
// doesn't works
1.print
// works
stringPrintable.print(1)
// works
intToString(1).print
Your code is requiring the additional implicit, because it is required as a constructor for your (implicit class) PrintableOps
You can simplify this by simply declaring implicit classes more directly:
trait Printable[T] {
def print: String
}
implicit class GenericPrintable[T](in: T) extends Printable[T] {
def print:String = in.toString
}
implicit class StringPrintable(in:String) extends Printable[String]{
override def print:String = s"print ${in}"
}
println( 1.print )
println( "1".print )
Your stringPrintable would require to use intToString to convert Int to String.
implicit val stringPrintable: Printable[String] = Printable((in: String) => s"print $in")
implicit def intToString(i: Int): String = i.toString
Printable.apply() requires an anonymous function and an anonymous function can't take an implicit value where intToString is implicit.
A better workaround is to statically define an implicit Printable[Int] or reform the Printable to GenericPrintable[T] with reference to #Jon Anderson
We need to provide an implicit conversion from Printer[String] => Printer[Int] given an implicit conversion from Int => String. We can put this on Printer companion object:
implicit def apply[T0, T1](implicit pin: Printable[T0], c: T1 => T0): Printable[T1] = new Printable[T1] {
def print(in: T1): String = pin.print(c(in))
}
Here the solution:
trait Printable[T]{
def print(in: T): String
}
object Printable{
def apply[T](f: T => String): Printable[T] = new Printable[T] {
def print(in: T): String = f(in)
}
implicit def apply[T0, T1](implicit pin: Printable[T0], c: T1 => T0): Printable[T1] = new Printable[T1] {
def print(in: T1): String = pin.print(c(in))
}
}
implicit class PrintableOps[T](v: T)(implicit printable: Printable[T]) {
def print: String = printable.print(v)
}
implicit val stringPrintable: Printable[String] = Printable((in: String) => s"print $in")
implicit def intToString(i: Int): String = i.toString
// now working
1.print
// works
stringPrintable.print(1)
// works
intToString(1).print
// don't compile, and it's ok, because no implicit conversion (A => String) is provided
case class A(in: String)
A("A").print
What do you think?