I try to use shapless lenses of version 2.0.0 for scala 2.10.3
I have the code similar to this one:
import shapeless._
case class A(map: Map[String, String])
case class B(a: A)
val mapLens = lens[B] >> 'a >> 'map
the infered type in idea of mapLens is
AnyRef with Lens[B, Nothing] {val gen: LabelledGeneric.Aux[Nothing, ::[record.FieldType[Witness.Lt[Symbol]#T, Nothing], Nothing]]}
so if I want to change value of B instance
mapLens.set(b)(b.a.map + ("foo" -> "bar"))
I get a type mismatch error. How to fix this?
P.S. Here there is an example of using shapeless lenses. How does this lens[Person].address.street works? I mean how does compiler allow us to call methods of case class on instance of lense class? Because in LenseExamples object the >> operator is used
edit
Have tried in REPL and it works. Idea says that it
could not find implicit value for evidence parameter of type shapeless.LabelledGeneric[B]{type Repr = Out0}
The same complain emits gradle
Idea is wrong. You should report a bug against the Scala plugin.
Related
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.
Here's two piece of example code, found here:
scala> val im = m.reflect(new C)
im: reflect.runtime.universe.InstanceMirror = instance mirror for C#3442299e
and here:
scala> def mkArray[T : ClassTag](elems: T*) = Array[T](elems: _*)
the first piece of code uses a method defined in scala.reflect.api.Mirrors (found here):
abstract def reflect[T](obj: T)(implicit arg0: ClassTag[T]): Universe.InstanceMirror
if you notice, there's a ClassTag used like ClassTag[T] and one used like ClassTag. What's the reason for the difference?
For the most part, both are equivalent.
foo[T: ClassTag]()
is syntactic sugar for
foo[T]()(implicit ct: ClassTag[T]
However, the difference between these signatures is that in the former, you have to access the ClassTag via implicitly[ClassTag[T]] while in the latter, you can just use ct
Syntax change note:
Before 2.10.x it used to not be possible to have have both a context bound like ClassTag and an implicit argument list, such as:
foo[T: ClassTag]()(implicit ex: ExecutionContext)
The error used to be reported as "Error: cannot have both implicit parameters and context bounds". IntelliJ 13 was still reporting it as late as 2.10.4, but is now accepted by the scala compiler.
scala> class A[T]
defined class A
scala> class B[T](a: A[T])
defined class B
scala> val b = new B(new A[Int])
b: B[Int] = B#1ff8982d
Great! I can create instances of B from instances of A. With one exception. For instances of A[Nothing] the type inference fails.
scala> val b = new B(new A[Nothing])
<console>:9: error: type mismatch;
found : A[Nothing]
required: A[T]
Note: Nothing <: T, but class A is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
val b = new B(new A[Nothing])
Specifying the type manually works.
scala> val b = new B[Nothing](new A[Nothing])
b: B[Nothing] = B#3aad5958
Should I file a bug for it, or is it an intentional trap to scare away programmers that lack sufficient resolve for Scala?
The answer is in the compilation feedback. You need to declare A as being covariant in T, so that when you don't specify the type parameter during the construction of a new B, the compiler can infer that the A[Nothing] may be treated as type T (or treat the A[T] parameter as a T). That's be basic idea behind covariance.
This has been known and ignored as issue SI-1570 since 2008. The assumption is that nobody uses Scala for anything serious.
Can someone point me at what I should be doing under scala 2.10 in place of this deprecated type witness on Manifest?
reflect.ClassManifest.singleType(foo) <:< barManifest
Honestly, my goal here is just to replace it with something that doesn't raise a deprecation warning. I'm happy to use the new reflection API.
Here's the code in question in context, if that's important:
https://github.com/azavea/geotrellis/blob/master/src/main/scala/geotrellis/feature/op/geometry/geometry.scala#L45
If you want a fairly literal translation from manifests to type tags, you'll need to get the appropriate mirror, use it to reflect your instance, and then use the <:< on Type. For example:
import scala.reflect.runtime.currentMirror
import scala.reflect.runtime.universe._
sealed trait X
case class Y(i: Int) extends X
case class Z(j: String) extends X
def filterX[A <: X: TypeTag](xs: List[X]) = xs.filter(
x => currentMirror.reflect(x).symbol.toType <:< typeOf[A]
)
And now:
scala> filterX[Z](List(Y(1), Y(2), Z("test")))
res1: List[X] = List(Z(test))
scala> filterX[Y](List(Y(1), Y(2), Z("test")))
res2: List[X] = List(Y(1), Y(2))
There may be ways you could take advantage of the new Reflection API more fully in your application, but this should work and will take care of the deprecation warnings.
Just wondering if the following is a bug or a feature:
Welcome to Scala version 2.10.0-M3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0).
Type in expressions to have them evaluated.
Type :help for more information.
scala> class TypeClass[T]
defined class TypeClass
scala> trait A[T] {
| implicit val t = implicitly[TypeClass[T]]
| }
<console>:9: error: could not find implicit value for parameter e: TypeClass[T]
implicit val t = implicitly[TypeClass[T]]
^
As expected, this doesn't compile because there's no constraint on T. But when I add a type annotation it compiles:
scala> trait A[T] {
| implicit val t: TypeClass[T] = implicitly[TypeClass[T]]
| }
defined trait A
Shouldn't the compiler be complaining here? Why should a type annotation make a difference? If we instantiate something with this trait, t is null.
Actually, you are just scr**ing yourself here. :-)
You just declared that the implicit TypeClass[T] is val t. That is, val t = t, which makes it null. Ouch!
T is abstract, so the compiler cannot provide a TypeClass for it. You'd have to get that with the T parameter, but you won't be able to in a trait. In a class, make it T : TypeClass.
I'd say it's neither bug nor feature, just a consequence of some features.
In the first example, there is no implicit value of type TypeClass[T] in scope. You rely on type inference to know the type of t and since implicits are resolved at compile time, the type of t is not defined because the implicit value can't be found.
In the second example there is a suitable implicit value in scope, namely t. If you did not allow that behavior in general you couldn't do recursive definitions like:
val fibs: Stream[Int] = 0 #:: 1 #:: fibs.zip(fibs.tail).map{case (x,y) => x+y}