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)
}
Related
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.
For example I have this simplified model where timestamp and duration both represent seconds.
case class Item(id: Int, : Long, duration: Int)
val max_timestmap: Long = ???
val stmt = items.filter(x => (x.timestamp + x.duration) <= max_timestamp)
db.run(stmt.result)
Above will not compile with following error that I have hard time understanding.
ambiguous implicit values:
[error] both value BooleanOptionColumnCanBeQueryCondition in object CanBeQueryCondition of type => slick.lifted.CanBeQueryCondition[slick.lifted.Rep[Option[Boolean]]]
[error] and value BooleanCanBeQueryCondition in object CanBeQueryCondition of type => slick.lifted.CanBeQueryCondition[Boolean]
[error] match expected type slick.lifted.CanBeQueryCondition[Nothing]
[error] filter(x => (x.timestamp + x.duration) <= max_timestamp)
Update 1:
Seems like the issues stems for the fact that timestamp is Long and duration is Int. When both are of the same data type it seems to compile.
Update 2:
I found this solution to work. Cast duration to Long using x.duration.asInstanceOf[Rep[Long]] or probably more appropriate x.duration.asColumnOf[Long]
According to Slick documentation COMING FROM SQL TO SLICK:
Arithmetic operation in different types require explicit casts using .asColumnOf[T].
As you have already discovered, you have to explicitly cast duration to Long: x.duration.asColumnOf[Long].
Though not very helpful in telling the exact problem, the error message makes sense if one looks at method filter and trait/object CanBeQueryCondition in Query.scala:
sealed abstract class Query[+E, U, C[_]] extends QueryBase[C[U]] { self =>
...
def filter[T <: Rep[_]](f: E => T)(implicit wt: CanBeQueryCondition[T]): Query[E, U, C] =
withFilter(f)
...
}
...
trait CanBeQueryCondition[-T] extends (T => Rep[_])
object CanBeQueryCondition {
implicit val BooleanColumnCanBeQueryCondition : CanBeQueryCondition[Rep[Boolean]] =
new CanBeQueryCondition[Rep[Boolean]] {
def apply(value: Rep[Boolean]) = value
}
implicit val BooleanOptionColumnCanBeQueryCondition : CanBeQueryCondition[Rep[Option[Boolean]]] =
new CanBeQueryCondition[Rep[Option[Boolean]]] {
def apply(value: Rep[Option[Boolean]]) = value
}
implicit val BooleanCanBeQueryCondition : CanBeQueryCondition[Boolean] =
new CanBeQueryCondition[Boolean] {
def apply(value: Boolean) = new LiteralColumn(value)
}
}
As pointed out by #Federico Pellegatta, the explicit cast requirement leads to T = Nothing (T <: Rep[_]) for the implicit parameter CanBeQueryCondition[T], thus the reported error.
I want to define a compression method that compresses a collection of a certain type Int or String into a string. I wanted to combine the two methods that I currently have:
def compressString[T <: IndexedSeq[String]]: (T) =>
String = (array: T) => array.mkString(" ")
def compressInt[T <: IndexedSeq[Int]]: (T) =>
String = (array: T) => array.mkString(" ")
Into one method. I tried to do higher kinded type with T[Int] but it didn't work that way. I also tried to do:
def compress[U, T <: IndexedSeq[U]]: (T) => String =
(array: T) => array.mkString(" ")
However, the compiler gives me this error:
[error] type mismatch;
[error] found : Iterator[Int(in method compress)]
[error] required: Iterator[scala.Int]
[error] collect(array.iterator, Vector.empty[String], 0).mkString("\t")
[error] ^
[error] SVM.scala:55: type mismatch;
[error] found : java.lang.String
[error] required: String(in method compress)
[error] override def compress[String, T <: IndexedSeq[String]]: (T) => String = (array: T) => array.mkString("\t")
In general, I want to eventually override this method and provide concrete implementation (the method that deals with Int is different from String). How do I combine these two methods??
In order to make your generic method compile, you need to pass the first type argument as the type of IndexedSeq, i.e.
def compress[U, T <: IndexedSeq[U]]: (T) => String = {
(array: T) => array.mkString(" ")
}
then you can invoke it like,
val strings = compress[String,Vector[String]](Vector("a","b")) // strings: String = a b
val ints = compress[Int,Vector[Int]](Vector(1,2)) // ints: String = 1 2
However, I think a type class would fit much better in the case that you want to have ad hoc polymorphism.
For example, you can define the following type class:
#implicitNotFound("No compressor found for type ${T}")
trait Compressor[T] {
def compress(array: IndexedSeq[T]): String
}
and create an implementation for every type that you want to support compression
implicit val stringCompressor = new Compressor[String] {
override def compress(array: IndexedSeq[String]): String = array.mkString(" ")
}
implicit val intCompressor = new Compressor[Int] {
override def compress(array: IndexedSeq[Int]): String = array.mkString(" ")
}
then you can call the methods directly
val strings = stringCompressor.compress(Vector("a","b")) // strings: String = a b
val ints = intCompressor.compress(Vector(1,2)) // ints: String = 1 2
or you can define a generic method that takes an implicit parameter
def compress[T](array: IndexedSeq[T])(implicit compressor: Compressor[T]): String = {
compressor.compress(array)
}
// or equivalently
def compress[T: Compressor](array: IndexedSeq[T]): String = {
implicitly[Compressor[T]].compress(array)
}
and use like this
val strings = compress(Vector("a","b")) // strings: String = a b
val ints = compress(Vector(1,2)) // ints: String = 1 2
if there is no implicit compressor defined in the scope, the compiler will give you an error, e.g.
compress(Vector(true, false))
error: No compressor found for type Boolean
compress(Vector(true, false))
^
Hope it helps.
The following fails to compile with Scala 2.11.4:
trait Test {
type A
type F = Function1[A, String]
}
trait Util[T <: Test] {
def compute1( f: T#A => String, a: T#A ): String = f(a)
def compute2( f: T#F, a: T#A ): String = f(a)
// ^
}
There is a compile error on the argument of the call (^):
type mismatch;
found : a.type (with underlying type T#A) required: _3317.A
I was expecting that the two f arguments in compute1 and compute2 would have the same type; apparently not.
What's going on?
As #Eugene and #Zim-Zam replied, the problem here is due to Scala's path-dependent types. Based on their suggestions, I came up with several alternatives:
trait Test {
type A
type Fa = Function1[A, String] // original question
type Fb = Function1[Test#A, String] // Zim-Zam's suggestion
}
trait TestOps[T <: Test] {
type G = Function1[T#A, String]
}
trait Util[T <: Test] {
def compute1( f: T#A => String, a: T#A ): String = f(a)
// def compute2a( f: T#Fa, a: T#A ): String = f(a)
// type mismatch; found : a.type (with underlying type T#A) required: _1536.A
def compute2b( f: T#Fb, a: T#A ): String = f(a)
}
trait Util1 {
def compute3a(t: Test)( f: t.Fa, a: t.A ): String = f(a)
def compute3b(t: Test)( f: t.Fb, a: t.A ): String = f(a)
}
trait Util2[T <: Test] { tops: TestOps[T] =>
// def compute4a( f: T#Fa, a: T#A ): String = f(a)
// type mismatch; found : a.type (with underlying type T#A) required: _1642.A
def compute4b( f: T#Fb, a: T#A ): String = f(a)
def compute5( f: tops.G, a: T#A ): String = f(a)
}
Util compares the original operation with #Zim-Zam's suggestion
Util1 exercises the difference in specifying the Function1 argument type: A vs Test#A
Util2 exercises the suggestion to define the Function1 type to another trait: TestOps
Commenting out the variations that don't type check, we're left with:
compute1
compute2b
compute3a
compute3b
compute4b
compute5
Which is better for specializing these traits?
To tease out the differences, I made a simple refinement:
class U
class TestU extends Test {
override type A = U
}
class UOps extends TestOps[TestU]
Here are the results:
trait UtilU extends Util[TestU] {
def get1( f: TestU#A => String, a: TestU#A) = compute1(f, a)
// def get2b( f: TestU#A => String, a: TestU#A) = compute2b(f, a)
// type mismatch; found : A.U ⇒ String required: A.Test#A ⇒ String
}
trait UtilU1 extends Util1 {
val u = new TestU()
def get3a( f: u.A => String, a: u.A) = compute3a(u)(f, a)
// def get3b( f: u.A => String, a: u.A) = compute3b(u)(f, a)
// type mismatch;
// found : UtilU1.this.u.A ⇒ String (which expands to) A.U ⇒ String
// required: UtilU1.this.u.Fb (which expands to) A.Test#A ⇒ String
}
class UtilU2 extends Util2[TestU] with TestOps[TestU] {
// def get4b( f: TestU#A => String, a: TestU#A) = compute4b(f, a)
// type mismatch; found : A.U ⇒ String required: A.Test#A ⇒ String
def get5( f: TestU#A => String, a: TestU#A) = compute5(f, a)
}
So, we're left with only 3 reasonable variations:
compute1 (no Function1 type alias)
compute3a
compute5
For aliasing Function1 types, we're left with just 2 alternatives: compute3a and compute5
What are the proper ways to describe the differences between them?
It's because of the way how path-dependent types implemented in scala
val test1 = new Test {}
val test2 = new Test {}
// test1.A is different type from test2.A
in your example you are basically saying that f and a can be passed from different instances of Test, and in this case A used in type F in first argument will be different A from second argument.
But if you'll restrict it to some instance of T it will compile
def compute2(t: T)( f: t.F, a: t.A ): String = f(a)
Upd
However it still should be the case for compute1
#Eugene is correct about this being caused by path dependent types - you can fix it with
trait Test {
type A
type F = Function1[Test#A, String]
}
Now F can take any A as its argument
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
}