The toArray call in following code does not compile
trait A[T] {
def create:T
def foo(a:Array[Int]) = {
for(b <- a) yield create
}.toArray
}
It throws the following errors:
not enough arguments for method toArray: (implicit evidence$1: scala.reflect.ClassTag[T])Array[T]. Unspecified value parameter evidence$1.
No ClassTag available for T
How do I fix it?
As Sergey said, Java arrays need to know the type of T, but T is eliminated by type erasure.
In scala you can "preserve" a type information at runtime using a ClassTag.
Here's a more in-depth discussion about arrays.
As per fixing it, you need to provide evidence of a ClassTag for T. Here's a possible solution:
import scala.reflect.ClassTag
trait A[T] {
def create: T
def foo(a: Array[Int])(implicit ev: ClassTag[T]) = {
for(b <- a) yield create
}.toArray
}
The implicit ev parameter is filled in automatically by the compiler.
The problem is that you can't create an Array[T] without knowing T. The ClassTag is Scala's way of representing this information. The simple fix would be to change trait A[T] to abstract class A[T: ClassTag] (class is needed because traits can't have any constructor parameters, including implicit ones). If you then create it with a specific type, e.g. class B extends A[Int], the compiler will insert the correct ClassTag itself, with a generic you need to pass the ClassTag through: class C[T: ClassTag] extends A[T].
The simplest way is to remove toArray call. Because you iterate over array so your result will be array too.
Related
I have some scala 2.13 code that basically boils down to this
import scala.language.implicitConversions
trait Base {
type V
def v: V
}
case class Derived(v: Int) extends Base {
type V = Int
}
object TestImplicitConversion {
implicit def getV[T <: Base](a: T): T#V = a.v
val a: Int = Derived(5)
}
Here I would expect the compiler to use the implicit conversion getV to convert Derived to Int, but the code does not compile. Manually adding the call to getV, will make the code compile. Can someone help me understand why the conversion where in the standard it is explained.
The way I found of making such a conversion work is by adding a second generic parameter and a constraint
implicit def getV2[T <: Base, S](a: T)(implicit constraint: T#V =:= S): S = constraint(a.v)
with this version the compiler uses the conversion and the code does compile.
Edit:
The alternative solution provided by #user using refinement type does indeed seem like a better approach. But it does not really provide an answer to why it original implementation does not work. So I am still interested in understanding why the compiler does not use the implicit def when an explicit call will make the code compile.
As gianluca aguzzi mentioned in the comments, type projection is unsound and should be avoided. Moreover, T is not a concrete type, so you can't use projections on it anyway. You can accept only Base#V as a type parameter instead, and use a refinement type for the type of a:
implicit def get[T](a: Base { type V = T }): T = a.v
Thus, you can avoid casting and type projections.
Scastie
Consider the following example:
sealed trait ST
object ST{
case class ST1() extends ST
case class ST2() extends ST
}
trait TypeClass[A]{
def doSome(a: A): Unit
}
case class Test[T](t: T)
implicit val tp: TypeClass[Test[_ <: ST]] = ??? //the implicit
def foo[A: TypeClass](a: A) = implicitly[TypeClass[A]].doSome(a)
val v: Test[_ <: ST] = ???
foo(v) //error: implicit not found
SCASTIE
As can be seen the required implicit is in scope while it is not recognized by the compile.
Why does that happen and is there a workaround to call foo?
If you change foo(v) to foo(v)(tp) it'll explain (a little bit) better why it doesn't want to use tp.
In a nutshell, def foo[A : TypeClass] wants an implicit of type TypeClass[A].
When you do foo(v), A becomes Test[_ <: ST] which means "Test of some specific but unknown subtype of ST". So, foo wants an implicit for that specific type.
But tp is not that. It is a "TypeClass for Test or any subclass of ST" (apparently _ means slightly different things in these two contexts, because v is a concrete instance, that must have a specific type).
Long story short, Test[_ <: ST] is not the actual type of v, but a supertype of its type. So, to make it work, you just need to make the TypeClass contravariant (TypeClass[-A]) - that'll make foo accept tp as the implicit, because its type will be a subtype of what it expects.
Existential types are not inferred during implicit resolution so f(v) fails because it is looking for an implicit value with non-inferred type
TypeClass[Test[_$4]]]
|
existential not inferred
however whey you explicitly provide the type variable instance foo[Test[_ <: ST]](v) then implicit resolution should work because we are past inference stage.
It works in Scala 3 probably because internally it rewrites existential types to refined types.
Trying to figure out why the code compiles for nested type inference on method with arity-2 but not with currying.
object Test
{
trait Version
object VersionOne extends Version
trait Request[A <: Version]
trait RequestOne extends Request[VersionOne.type]
case class HelloWorld() extends RequestOne
def test1[A <: Version, T <: Request[A]](t : T, a : A): T = t
def test2[A <: Version, T <: Request[A]](t : T)(a : A): T = t
}
// This works
Test.test1(Test.HelloWorld(), Test.VersionOne)
// This doesn't
Test.test2(Test.HelloWorld())(Test.VersionOne)
test2 fails to compile with the following error:
Error:(22, 73) inferred type arguments [Nothing,A$A96.this.Test.HelloWorld] do not conform to method test2's type parameter bounds [A <: A$A96.this.Test.Version,T <: A$A96.this.Test.Request[A]]
def get$$instance$$res1 = /* ###worksheet### generated $$end$$ */ Test.test2(Test.HelloWorld())(Test.VersionOne)
Looking forward to some insights on the same.
#DmytroMitin already explained why it does fail.
However, you can solve the problem this way, using the Partially-Applied Type trick, together with Generalized Type Constraints.
def test2[T](t: T): Test2PartiallyApplied[T] = new Test2PartiallyApplied(t)
final class Test2PartiallyApplied[T](private val t: T) extends AnyVal {
def apply[A <: Version](a: A)(implicit ev: T <:< Request[A]): T = t
}
Which you can use like this.
Test.test2(Test.HelloWorld())(Test.VersionOne)
// res: HelloWorld = HelloWorld()
Nothing in compile error usually means that some type parameters were not inferred.
Try to specify them explicitly
Test.test2[Test.VersionOne.type, Test.RequestOne](Test.HelloWorld())(Test.VersionOne)
Difference between test1 and test2 is not only in currying. For example, generally in test2(t: ...)(a: ...) type of a can depend on value of t. So for test2 type inferrence is more complicated than for test1.
Scala type inference and multiple arguments list
Type inference with type aliases and multiple parameter list function
Multiple parameter closure argument type not inferred
What's the difference between multiple parameters lists and multiple parameters per list in Scala?
Having this type class for converting a Map into a case class:
/**
* Type class for transforming a map of values into a case class instance.
*
* #tparam T Wanted case class type.
*/
#implicitNotFound("Missing ToCaseClassMapper implementation for type ${T}")
trait ToCaseClassMapper[T <: Product] {
def toCaseClass(map: Map[String, Any]): T
}
And this function to implicitly get the correct mapper
def toCaseClass[T <: Product](map: Map[String, Any])(implicit mapper: ToCaseClassMapper[T]): T = {
mapper.toCaseClass(map)
}
It can be used as toCaseClass[User](aUserMap) // returns User
But I also would like to be able to use this function with an Option[Map[]] or Future[Map[]] or List[Map[]].
So I implemented a generic function using a functor like this:
def toCaseClass[T <: Product, F[_]: cats.Functor](fOfMaps: F[Map[String, Any]])(implicit mapper: ToCaseClassMapper[T]): F[T] = {
cats.Functor[F].map(fOfMaps)(map => toCaseClass(map)(mapper))
}
But now this function has to be used as toCaseClass[User,List](listOfUserMaps) // returns List[User].
However, I'd would like to be able to use the function as
toCaseClass[User](listOfMaps)
toCaseClass[User](futureOfMap)
toCaseClass[User](optionOfMap)
without the need to specify the functor type.
Is this somehow possible?
Could Shapeless's Lazy be used to solve this?
Edit: solution
Thanks to #Jasper-m and #dk14 for their answers.
So the 'trick' to solve this is to capture the type 'T' first in a class before the Functor type. I liked #Jasper-m solution with the 'apply' method since that would keep the syntax almost similar to what it was before.
I made a few adjustments though. Since there was already the 'ToCaseClassMapper' class which also captures the type 'T', I decided to combine it with the 'ToCaseClass' class. Also, with #Jasper-m's approach, when using the 'toCaseClass' function when mapping over some value like Option(value).map(toCaseClass) the usage of toCaseClass had to be different for when the value was a Map or a List[Map].
My solution is now as follows:
#implicitNotFound("Missing ToCaseClassMapper implementation for type ${T}")
trait ToCaseClassMapper[T <: Product] {
def toCaseClass(map: Map[String, Any]): T
import scala.language.higherKinds
def toCaseClass[F[_]: cats.Functor, A](fOfMaps: F[Map[String, A]]): F[T] = {
cats.Functor[F].map(fOfMaps)(toCaseClass)
}
}
Since the ToCaseClassMapper instance was already implicitly available where the toCaseClass function was used, I decided to throw away that function and just replace it with mapper.toCaseClass(_). This cleaned up some unneeded code and now the syntax for using the mapper is the same regardless whether the value is a Map or Option, List, Future (or any other Functor).
Currently it's not possible in Scala to have one type parameter provided explicitly and another one in the same type parameter list be inferred, nor is it currently possible to have multiple type parameter lists for a method. A workaround is to create a helper class and split your method call in two stages: first create an instance of the helper class, then call the apply method on that object.
class ToCaseClass[T <: Product] {
def apply[F[_]: cats.Functor, A](fOfMaps: F[Map[String, A]])(implicit mapper: ToCaseClassMapper[T]): F[T] = {
cats.Functor[F].map(fOfMaps)(map => toCaseClass(map)(mapper))
}
}
def toCaseClass[T <: Product] = new ToCaseClass[T]
def toCaseClass[T <: Product](map: Map[String, Any])(implicit mapper: ToCaseClassMapper[T]): T = {
mapper.toCaseClass(map)
}
toCaseClass[User](listOfMaps)
toCaseClass[User](futureOfMap)
toCaseClass[User](optionOfMap)
Edit: As pointed out by dk14, there is still a type inference problem here, where F is inferred as Any. I don't know what causes it, but I think it is a separate orthogonal problem from the one being solved by this pattern.
Edit 2: I figured it out. It's because F is invariant in its type parameter. F[Map[String, String]] is not a subtype of F[Map[String, Any]], so the compiler does something strange and infers F as Any. A solution is to put a type parameter A instead of Any, or use an existential type Map[String,_].
This works:
class Mapper[T <: Product](implicit val mapper: ToCaseClassMapper[T]){
def toCaseClass[F[_]: cats.Functor, Z <: Map[String, Any]](fOfMaps: F[Z]): F[T] = {
cats.Functor[F].map(fOfMaps)(map => mapper.toCaseClass(map))
}
}
object Mapper{
def apply[T <: Product: ToCaseClassMapper] = new Mapper[T]{}
}
import cats.implicits._
Mapper[User].toCaseClass(List(Map("aaa" -> 0)))
Few tricks besides obvious introducing class (to split type parameters) were used as well:
1) move mapper to constructor so it could be resolved first (not sure it helped)
2) what definitely helped is to introduce Z <: Map[String, Any], otherwise scala (at least my old version 2.11.8) would infer F[_] as Any for some reason
P.S. You can use apply instead of toCaseClass as well - it would shorten the syntax
I would like to add an implicit parameter to a class with a private constructor. Here as a simplified example:
class A[T] private(a:Int){
def this()=this(0)
}
If I would like to apply Pimp my library pattern to T with Ordered[T], I would need to use (the deprecated) view bound like so:
class A[T <% Ordered[T]] private(a:Int){
def this()=this(0)
}
And this works. However, to avoid the deprecated syntactic sugar I would like to pass the implicit parameter to the class. Unfortunately, this is where I'm probably doing something wrong:
class A[T] private(a:Int)(implicit conv:T=>Ordered[T]){
def this()=this(0)
}
For the above code, the compiler generates the following error:
error: No implicit view available from T => Ordered[T].
def this()=this(0)
While if I try to pass the implicit parameter directly like so:
class A[T] private(a:Int)(implicit conv:T=>Ordered[T]){
def this()=this(0)(conv)
}
I get this:
error: not found: value conv
def this()=this(0)(conv)
How does one pass an implicit parameter in this case?
EDIT: After some more experimentation it seems that redefining the constructor with implicit parameter is the problem. Not the fact that the constructor is private.
I found an answer, it seems that I need to explicitly define the implicit parameter for the parameterless constructor, e.g.:
class A[T] private(a:Int)(implicit conv:T=>Ordered[T]){
def this()(implicit conv:T=>Ordered[T])=this(0)
}
I apologize for spamming SO, in any case I will accept any answer that provides a more in depth explanation.
Scala provides ordering in 2 flavours, one via inheritance with Ordered and the other one which is actually a lot more appropriate in here is via context bounds using the Ordering typeclass.
Your approach is not actually idiomatic, and if you had something that actually used the implicit you provided, you would get an ambiguous implicit exception at compile time, because both the constructor and the method define the same implicit.
What I would do is:
class A[T : Ordering] private(a: Int)
This is actually shorthand syntax for:
class A[T] private(a: Int)(implicit ev: Ordering[T])
You can then use this argument either explicitly or implicitly.
If you define it with the shorthand T : Ordering syntax.
class A[T : Ordering] private(a: Int) {
def revSorter(list: List[T]): List[T] = {
list.sorted(implicitly[Ordering[T]].reverse)
}
}
If you define it with the "explicit" syntax:
class A[T] private(a: Int)(implicit ev: Ordering[T]) {
def revSorter(list: List[T]): List[T] = {
list.sorted(ev.reverse)
}
}