I have the following code, that does not get compiled:
final class DbSystemEnvironment[F[_] : MonadError[F, Throwable]] private(env: Environment[F])
extends DbSetting[F] {
override def read(url: String, user: String, pw: String): F[DbParameter] =
(for {
a <- OptionT(env.get(url))
b <- OptionT(env.get(user))
c <- OptionT(env.get(pw))
} yield DbParameter(a, b, c))
.value
.flatMap {
case Some(v) => v.pure[F]
case None => DbSettingError.raiseError[F, DbParameter]
}
}
The compiler complains:
[error] db/DbSystemEnvironment.scala:10:38: cats.MonadError[F,Throwable] does not take type parameters
[error] final class DbSystemEnvironment[F[_] : MonadError[F, Throwable]] private(env: Environment[F])
[error] ^
[error] db/DbSystemEnvironment.scala:16:9: Could not find an instance of Functor for F
[error] c <- OptionT(env.get(pw))
[error] ^
[error] db/DbSystemEnvironment.scala:20:27: value pure is not a member of Any
[error] case Some(v) => v.pure[F]
[error] ^
[error] db/DbSystemEnvironment.scala:21:37: value raiseError is not a member of object io.databaker.db.DbSettingError
[error] case None => DbSettingError.raiseError[F, DbParameter]
It seems, that I do not use MonadError correctly.
The rest of the code:
final case class DbParameter(url: String, user: String, pw: String)
trait Environment[F[_]] {
def get(v: String) : F[Option[String]]
}
object Environment {
def apply[F[_]](implicit ev: Environment[F]): ev.type = ev
def impl[F[_]: Sync]: Environment[F] = new Environment[F] {
override def get(v: String): F[Option[String]] =
Sync[F].delay(sys.env.get(v))
}
}
How to get the code compiled?
The issue here is the constraint syntax. For a type constructor with a single parameter (like Monad), you can write class Foo[F[_]: Monad]. When you need to "partially apply" a type constructor with multiple parameters, like MonadError, the situation is slightly different.
If you're using kind-projector, you can write the following:
class DbSystemEnvironment[F[_]: MonadError[*[_], Throwable]]
This is non-standard syntax, though, and it isn't currently included in Dotty's partial -Ykind-projector compatibility support. I'd recommend just desugaring the implicit parameter list:
class DbSystemEnvironment[F[_]](implicit F: MonadError[F, Throwable]])
This does exactly what you want, doesn't require an extra compiler plugin, and is much more future-proof.
Related
Suppose I have trait that represents something like a polymorphic function, e.g.:
trait Func[A[X, Y]] {
def apply[X, Y](a: A[X, Y]): A[X, Y]
}
Now I want to use my trait as a non-polymorphic function by passing type lambda as argument:
type single[T] = { type t[X, Y] = T }
val aInstance: Func[single[String]#t] =
new Func[single[String]#t] {
def apply[X, Y](a: String): String = ???
}
Now I have method test which does some useful things with func, e.g.
def test[A[X, Y]](f: Func[A]): Unit = ???
And I want to invoke test with aInstance without specifying type parameters by hand:
test(aInstance)
Unfortunately, this code does not compile (but test[single[String]#t](aInstance) does) with error messages:
[error] /test.scala:16:3: no type parameters for method test: (f: Func[A])Unit exist so that it can be applied to arguments (Func[[X, Y]String])
[error] --- because ---
[error] argument expression's type is not compatible with formal parameter type;
[error] found : Func[[X, Y]String]
[error] required: Func[?A]
[error] test(aInstance)
[error] ^
[error] /test.scala:16:8: type mismatch;
[error] found : Func[[X, Y]String]
[error] required: Func[A]
[error] test(aInstance)
[error] ^
[error] two errors found
My question is: how can I modify these declarations to allow compiler to infer all required types automatically?
To those wondering why I declared Func as having [X, Y] but never used them in actual code there is a more real-world and less abstract example:
object GenericTest {
trait Item { def name: String }
class ItemA extends Item { def name: String = "a" }
class ItemB extends Item { def name: String = "b" }
trait MapFn[-A[X <: Item], +B[X <: Item]] {
def apply[X <: Item](data: A[X]): B[X]
}
case class ItemsCollection[C[A <: Item]](a: C[ItemA], b: C[ItemB]) {
def map[D[A <: Item]](f: MapFn[C, D]): ItemsCollection[D] =
ItemsCollection(f(a), f(b))
}
// sometimes we want to store sequences...
val itemSeq = ItemsCollection[Seq](Seq(new ItemA), Seq(new ItemB))
// or transform them:
val itemSet = itemSeq.map(new MapFn[Seq, Set] {
override def apply[X <: Item](data: Seq[X]): Set[X] = data.toSet
})
// but one day we wanted to store just objects without any item-specific types... e.g. names:
type single[X] = { type t[A] = X }
val itemNames = itemSeq.map(new MapFn[Seq, single[String]#t] {
override def apply[X <: Item](data: Seq[X]): String = data.head.name
})
/*
[error] test.scala:28:27: no type parameters for method map: (f: MapFn[Seq,D])ItemsCollection[D] exist so that it can be applied to arguments (MapFn[Seq,[A]String])
[error] --- because ---
[error] argument expression's type is not compatible with formal parameter type;
[error] found : MapFn[Seq,[A]String]
[error] required: MapFn[Seq,?D]
[error] val itemNames = itemSeq.map(new MapFn[Seq, single[String]#t] {
[error] ^
[error] test.scala:28:31: type mismatch;
[error] found : MapFn[Seq,[A]String]
[error] required: MapFn[Seq,D]
[error] val itemNames = itemSeq.map(new MapFn[Seq, single[String]#t] {
[error] ^
[error] two errors found
*/
}
Referring to your GenericTest, there is no way to get Scala to infer that shape, because of this closed-but-unfixed bug.
One thing you can do is try to adapt the technique of Unapply, using implicit resolution to determine the likely candidate for D. This will probably entail defining your own typeclass and instances, not using the ones Scalaz supplies, and possibly changing how MapFn is declared to be more suitable for this pattern. Make sure that the instance that gives you single has the lowest priority, as it can always be used (every T is an F[T] if F = Id).
If you control the definition of MapFn, you may also move the B type parameter to a type member. Then the signature of map becomes
def map(f: MapFn[C]): ItemsCollection[f.B] =
You can add a subclass to MapFn that moves the type member back to a parameter for ease of MapFn creation.
Using scala 2.12.4 I cannot get this code to work since it says
[error] .../src/main/scala/effect.scala:32:11: No ClassTag available for A
[error] Effect(effectDefinition)
[error] ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
here is the (simplified) code. the reason i need the class tag is to do a filtering later in the code (installEffect).
import scala.reflect.ClassTag
package object effect {
type EffectDefinition[A <: EffectBearing[A]] = A => Unit
case class Effect[A <: EffectBearing[A]](fx: A => Unit)(implicit tag: ClassTag[A]) {
def effectedType: Class[A] = tag.runtimeClass.asInstanceOf
}
trait EffectBearing[This <: EffectBearing[This]] {
def installEffect(effect: Effect[This]): Unit = {
effect.fx(this.asInstanceOf[This])
}
}
trait EffectPropagating {
def installEffect[T<: EffectBearing[T]](effect: Effect[T], typ: Class[T]): Unit =
find(typ).foreach(_.installEffect(effect))
protected def find[T <: EffectBearing[T]](typ: Class[T]): Set[T]
}
class Foo extends EffectBearing[Foo] {}
val fxFoo: EffectDefinition[Foo] = print(_)
def translate[A <: EffectBearing[A]](effectDefinition: EffectDefinition[A]): Effect[A] =
Effect(effectDefinition)
val fx = translate(fxFoo)
}
ps: is the usage of
tag.runtimeClass.asInstanceOf
very bad? I couldn't get around that cast
You have the following method:
def translate[A <: EffectBearing[A]](effectDefinition: EffectDefinition[A]): Effect[A] =
Effect(effectDefinition)
The Effect constructor requires an implicit ClassTag[A] but here A is a type parameter so the compiler doesn't know which concrete class it will be. And there is no ClassTag context bound on A in translate, so the compiler will not be able to find an implicit ClassTag[A].
I tried following this answer, but it did not help. Here's the implementation I have.
implicit class MyString(s: String) {
override def toBoolean = s.trim.toLowerCase match {
case "true" | "t" | "1" => true
case _ => false
}
}
And the error I am getting is:
[error] found : s.type (with underlying type String)
[error] required: ?{def toBoolean: ?}
[error] Note that implicit conversions are not applicable because they are ambiguous:
[error] both method augmentString in object Predef of type (x: String)scala.collection.immutable.StringOps
[error] and method MyString in trait ImplicitsStartingWithS of type (s: String)foo.MyString
[error] are possible conversion functions from s.type to ?{def toBoolean: ?}
[error] case Some(s) => s.toBoolean
[error] ^
I can't seem to find what's wrong with the code.
Other than the fact that toBoolean does not override anything, your implementation is fine. However, as the compiler error helpfully indicates, the name of your method clashes with the toBoolean method in the automatically imported StringOps class in Predef. As a result, there is more than one implicit conversion that could be applied and the compiler cannot decide which one to use. This is why the error indicates that there is ambiguity. The solution is to name your method differently, so the following should work.
implicit class MyString(s: String) {
def toBooleanAlt = s.trim.toLowerCase match {
case "true" | "t" | "1" => true
case _ => false
}
}
First, note that implicit conversions can't override methods in the type being converted from: if such a method exists, the compiler simply won't look for the implicit! There is a fork of Scala called Scala-Virtualized which does allow this (you'd define a method infix_toBoolean(x: String)), but I'd recommend against it for general usage: if you can't live without this feature check it out.
In this case, as #moem's answer says, the toBoolean isn't actually defined on String. As an alternative to simply giving a different name to your toBoolean, you can also explicitly hide augmentString in a class by defining something else with this name: def augmentString = ??? or
class MyString(s: String) {
def toBoolean = s.trim.toLowerCase match {
case "true" | "t" | "1" => true
case _ => false
}
}
implicit def augmentString(s: String) = new MyString(s)
Of course, this loses all other methods provided by this implicit as well, but you can provide them in MyString (e.g. by extending StringOps).
I am new to Scala - and while generating Excel files with Apache POI, I tried removing duplication in my code via this generic:
def addCell[A](
row: org.apache.poi.ss.usermodel.Row,
idxColumn: Int,
data: A)
:
Unit =
{
row.createCell(idxColumn).setCellValue(data)
}
Unfortunately, the compiler reported:
[error] .../mycode.scala:32: overloaded method value setCellValue \
with alternatives:
[error] (x$1: Boolean)Unit <and>
[error] (x$1: String)Unit <and>
[error] (x$1: org.apache.poi.ss.usermodel.RichTextString)Unit <and>
[error] (x$1: java.util.Calendar)Unit <and>
[error] (x$1: java.util.Date)Unit <and>
[error] (x$1: Double)Unit
[error] cannot be applied to (A)
[error] row.createCell(idxColumn).setCellValue(data)
[error] ^
[error] one error found
[error] (compile:compile) Compilation failed
I don't get it - whoever calls addCell will be passing a specific type A (the type of the 3rd argument, data) so the generic form should be able to dispatch to the proper overloaded form of setCellValue.
I am probably missing something obvious - any help most appreciated.
EDIT: To make it clear - my code is currently doing this:
field match {
case i:Int => row.createCell(idxCol).setCellValue(i)
case l:Long => row.createCell(idxCol).setCellValue(l)
case f:Float => row.createCell(idxCol).setCellValue(f)
case d:Double => row.createCell(idxCol).setCellValue(d)
case s:String => row.createCell(idxCol).setCellValue(s)
...
And I'd like to avoid the obvious repetition via a generic call to something like
field match {
case i:Int => setCell(row, idxCol, i)
case l:Long => setCell(row, idxCol, l)
case f:Float => setCell(row, idxCol, f)
...
Is it possible?
The most straightforward way is writing a separate method for each type:
def addCell(
row: org.apache.poi.ss.usermodel.Row,
idxColumn: Int,
data: Boolean)
:
Unit =
{
row.createCell(idxColumn).setCellValue(data)
}
def addCell(
row: org.apache.poi.ss.usermodel.Row,
idxColumn: Int,
data: String)
:
Unit =
{
row.createCell(idxColumn).setCellValue(data)
}
This is OK if you need just addCell to write this way.
If you need some code for more methods, you may consider a more advanced approach that limits the boilerplate per method.
A sketch of the more advanced approach:
Define a cellSetter trait, which can set a value of given type to the cell.
trait CellSetter[A]{
def setCell(cell: Cell, data: A): Unit
}
Implement CellSetters for all the relevant types, e.g.:
implicit val stringCellSetter = new CellSetter[String](){
def setCell(cell: Cell, data: String){
cell.setCellValue(data)
}
}
Make some sugar:
implicit class RichCell(cell: Cell){
def setCellValue[A](data: A)(implicit cellSetter: CellSetter[A]) = cellSetter.setCell(cell, data)
}
Create some nice generic code for addCell:
def addCell[A: CellSetter](
row: org.apache.poi.ss.usermodel.Row,
idxColumn: Int,
data: A)
:
Unit =
{
row.createCell(idxColumn).setCellValue(data)
}
Not that I ever do anything like this, but I was curious whether specialization helps.
Minimally, you'd like to avoid boxing the primitives.
It turns out that specialization doesn't help much, because specialized methods don't dispatch to unspecialized ones. I think I've read about this problem before.
In the following, specializing add works OK. One version uses a ClassTag to select a reference type, or the other one handles primitives. But the commented-out code just calls setCellValue(Any); it's not true that the boolean version calls setCellValue(Boolean).
The version commented-in seems to crash the back-end...
import scala.reflect.ClassTag
import java.util.Date
trait Setter {
def setCellValue(b: Boolean) = println("bool")
def setCellValue(s: String) = println("str")
def setCellValue(n: Double) = println("double")
def setCellValue(d: Date) = println("date")
}
object Test extends App {
def add[#specialized(Boolean, Double) A <: AnyVal](s: Setter, a: A) = {
/*
class ASetter extends Setter {
override def setCellValue(b: Boolean) = s setCellValue b
override def setCellValue(n: Double) = s setCellValue n
def setCellValue(x: Any) = ???
}
(new ASetter) setCellValue a
*/
a match {
case b: Boolean => s setCellValue b
case d: Double => s setCellValue d
case _ => ???
}
}
def add[A: ClassTag](s: Setter, a: A) = a match {
//case _: Boolean | _: Double => s setCellValue a
case d: Date => s setCellValue d
case x: String => s setCellValue x
case _ => ???
}
val s = new Setter {}
add(s, new Date)
add(s, true)
}
Fiddling with sample code demonstrating type bounds, I changed the original code below from using a case class to a plain class, for the definition of class MyInt, the only class in this snippet.
trait Similar {
def isSimilar(x: Any): Boolean
}
class MyInt(x: Int) extends Similar {
def isSimilar(m: Any): Boolean =
m.isInstanceOf[MyInt] &&
m.asInstanceOf[MyInt].x == x
}
object UpperBoundTest extends App {
def findSimilar[T <: Similar](e: T, xs: List[T]): Boolean =
if (xs.isEmpty) false
else if (e.isSimilar(xs.head)) true
else findSimilar[T](e, xs.tail)
val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3))
println(findSimilar[MyInt](MyInt(4), list))
println(findSimilar[MyInt](MyInt(2), list))
}
That no longer compiles
[error] 7: type mismatch;
[error] found : MyInt
[error] required: ?{def x: ?}
[error] Note that implicit conversions are not applicable because they are ambiguous:
[error] both method any2Ensuring in object Predef of type [A](x: A)Ensuring[A]
[error] and method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A]
[error] are possible conversion functions from MyInt to ?{def x: ?}
[error] m.asInstanceOf[MyInt].x == x
[error] ^
This is an interesting case to me, as sometimes I find myself refactoring case classes to plain classes while refactoring inheritance, and clearly some changes need to made in the code in order to enjoy a smooth transition that preserves the code working.
Switching .AsInstanceOf to an equivalent match (m match {case m:MyInt => m.x == x; case _ => false}) yields the same compilation error. Using a more naive match does not compile either:
trait Similar {
def isSimilar(x: Any): Boolean
}
class MyInt(x: Int) extends Similar {
def isSimilar(m: Any): Boolean = {
m match {case m:MyInt => true; case _ => false}
}
}
object UpperBoundTest extends App {
val a = new MyInt(4)
def findSimilar[T <: Similar](e: T, xs: List[T]): Boolean =
if (xs.isEmpty) false
else if (e.isSimilar(xs.head)) true
else findSimilar[T](e, xs.tail)
val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3))
println(findSimilar[MyInt](MyInt(4), list))
println(findSimilar[MyInt](MyInt(2), list))
}
18: not found: value MyInt
[error] val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3))
[error] ^
18: not found: value MyInt
[error] val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3))
[error] ^
18: not found: value MyInt
[error] val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3))
[error] ^
19: not found: value MyInt
[error] println(findSimilar[MyInt](MyInt(4), list))
[error] ^
20: not found: value MyInt
[error] println(findSimilar[MyInt](MyInt(2), list))
[error] ^
[error] 5 errors found
Are non-case classes a practice to be enitrely discouraged other than using them for inheriting them, or when you will never need to check their type? when would you ever use a non-case class?
Simply declare your class as
class MyInt(val x: Int) extends Similar
For case classes val is the default, whereas on regular classes you need to explicitly add it to signal that you want to synthesize the accessors for the constructor parameters
Also, in case classes a companion object providing a default apply method is automatically synthesized, allowing you to call
MyInt(2)
as opposed to
new MyInt(2)
You either have to use the latter, or manually provide an apply method in a companion object.
Bottom line, if you need to match on a class, case classes are much more convenient, as you can skip the downcast (which is implicitly performed when you match on the type doing x: MyInt)
Classes are not discouraged, simply case-classes are much more convenient in your specific use -case
Complete code you need to avoid compilation failure in any case, including pattern matching:
class MyInt(val x: Int) extends Similar
object MyInt {
def apply(x: Int) = new MyInt(x)
// if more than one field, return Some(tuple of all fields)
def unapply(myInt: MyInt): Option[Int] = Some(myInt.x)
}
If you also want behavior to be the same as original, you need to define equals and hashCode methods as well:
class MyInt(val x: Int) extends Similar {
def equals(y: Any) = y match {
case MyInt(z) => x == z
case _ => false
}
def hashCode = x
}