I am reading Section 19.3 of the book "programming in scala 2nd",
there is a snippet code and some description around it in page 431:
NOTE: FC17 x86_64 Scala-2.9.2
class Cell[T](init: T) {
private[this] var current = init
def get = current
def set(x: T) { current = x }
}
I modifyed this sample in two different enviroments:
in first one, I wrote the following code in a file Cell.scala
class A
class B extends A
class C extends B
class Cell[+T](init: T) {
private[this] var current = init
def get = current
def set[U >: T](x: U) {
current = x.asInstanceOf[T]
println("current " + current)
}
}
object Cell {
def main(args: Array[String]) {
val a1 = new Cell[B](new B)
a1.set(new B)
a1.set(new String("Dillon"))
a1.get
}
}
and using the following command, and got nothing error:
[abelard <at> localhost lower-bound]$ scalac Cell.scala
[abelard <at> localhost lower-bound]$ scala -cp . Cell
current B <at> 67591ba4
current Dillon
Dillon
[abelard <at> localhost lower-bound]$
in the second, I directly wrote the code under the REPL:
scala> class Cell[+T](init: T) {
| private[this] var current = init
| def get = current
| def set[U >: T](x: U) {current = x.asInstanceOf[T]
| }}
defined class Cell
scala> val a1 = new Cell[B](new B)
a1: Cell[B] = Cell <at> 6717f3cb
scala> a1.set(new B)
scala> a1.set(new String("Dillon"))
scala> a1.get
java.lang.ClassCastException:
java.lang.String cannot be cast to B
at .<init>(<console>:25)
at .<clinit>(<console>)
accordding to my uderstanding to covariant and lower-bound,
I think the second result is right, but I do not know why
the first one did not throw any error?
I know I must missing something, I want to get a compiling
error as the second, what should I do?
You're not going to get a compile error, because there's no problem at compile time. A ClassCastException is a runtime exception.
You should notice that the exception occurs after you evaluate a1.get, rather that when you perform the cast in a1.set. More precisely, it occurs when you try to assign that return value to a variable.
In your first scenario a1.get is not assigned to a value. In your second, you're assigning it to a value such as res0 etc.
You can show that this is the problem by trying the following in the REPL:
scala> a1.get
java.lang.ClassCastException: java.lang.String cannot be cast to B
scala> println(a1.get)
Dillon
Related
I am writing a compiler plugin to rewrite a function definition as a tuple of the function hash + function body
So the following
def f(a: Int, b: Int) : Int = (a + b)
would turn into
val f = ("some-complex-hash", (a: Int, b: Int) => (a + b))
Let me note that, this is for a research project and will be used to integrate some variant of reversible computations into a subset of the language. I am aware that, on its own, this is a bad idea and will break a lot of things.
The documentation of compiler plug in construction seems to be rather lacking (I did go through the official guide), so I am trying to make progress looking at existing plugins such as the kind-projector
In order to understand how to represent this, I have followed the following process
Reify the expression val expr = reify {....}
Extract the tree val tree = expr.tree
showRaw(tree)
I have done this for a function definition, tuple and a lambda, which I believe should be enough to implement this. I got the following so far:
ValDef(Modifiers(), TermName(dd.name), TypeTree(),
Apply(
Select(Ident("scala.Tuple2"), TermName("apply")),
List(
Literal(Constant(hash)),
Function(
List(dd.vparamss),
dd.rhs
)
)
)
)
Before I even get to this, I am having trouble with expanding to any tuple at all i.e. rewrite any function as ("a", "b") which expands to the following in the REPL
Apply(Select(Ident(scala.Tuple2), TermName("apply")), List(Literal(Constant("a")), Literal(Constant("b"))))
The Problem
If I do Ident(scala.Tuple2) I get the following at compile time
overloaded method value Ident with alternatives:
[error] (sym: FunctionRewriter.this.global.Symbol)FunctionRewriter.this.global.Ident <and>
[error] (name: String)FunctionRewriter.this.global.Ident <and>
[error] FunctionRewriter.this.global.Ident.type
[error] cannot be applied to (Tuple2.type)
[error] Select(Ident(scala.Tuple2), TermName("apply")),
If I do Ident("scala.Tuple2") (notice the string), I get the following when the plug in runs (at "run time")
<test>:2: error: not found: value scala.Tuple2
[error] object Main extends App {
I would appreciate any pointers on how to rewrite as Tuples
The Full Code:
class CompilerPlugin(override val global: Global) extends Plugin {
val name = "provenance-expander"
val components = new FunctionRewriter(global) :: Nil
}
class FunctionRewriter(val global: Global) extends PluginComponent with TypingTransformers {
import global._
override val phaseName = "compiler-plugin-phase"
override val runsAfter = List("parser")
override def newPhase(prev: Phase) = new StdPhase(prev) {
override def apply(unit: CompilationUnit) {
unit.body = new MyTypingTransformer(unit).transform(unit.body)
}
}
class MyTypingTransformer(unit: CompilationUnit) extends TypingTransformer(unit) {
override def transform(tree: Tree) : Tree = tree match {
case dd: DefDef =>
val hash: String = "do some complex recursive hashing"
Apply(
Select(Ident("scala.Tuple2"), TermName("apply")),
List(Literal(Constant("a")), Literal(Constant("b")))
)
case _ => super.transform(tree)
}
}
def newTransformer(unit: CompilationUnit) = new MyTypingTransformer(unit)
}
Thanks to #SethTisue for answering in the comments. I am writing up a answer for anybody who might face a similar issue in the future.
As Seth mentioned, using mkTuple was the right way to go. In order to use it, you need the following import
import global.gen._
In this specific case, as originally speculated in the question, the transformation breaks a lot of things. Mainly transforming the methods injected by object and class definitions i.e. for method dispatch or init, results in malformed structures. The work around is using explicit annotations. So the final DefDef ends up looking like the following:
case dd: DefDef =>
if (dd.mods.hasAnnotationNamed(TypeName(typeOf[policyFunction].typeSymbol.name.toString))) {
val hash: String = md5HashString(dd.rhs.toString())
val tup =
atPos(tree.pos.makeTransparent)(mkTuple(List(Literal(Constant(hash)), Function(dd.vparamss(0), dd.rhs))))
val q = ValDef(Modifiers(), dd.name, TypeTree(), tup)
println(s"Re-written Function: $q")
q
} else {
dd
}
Is there a way to get the Type of a field with scala reflection?
Let's see the standard reflection example:
scala> class C { val x = 2; var y = 3 }
defined class C
scala> val m = ru.runtimeMirror(getClass.getClassLoader)
m: scala.reflect.runtime.universe.Mirror = JavaMirror ...
scala> val im = m.reflect(new C)
im: scala.reflect.runtime.universe.InstanceMirror = instance mirror for C#5f0c8ac1
scala> val fieldX = ru.typeOf[C].declaration(ru.newTermName("x")).asTerm.accessed.asTerm
fieldX: scala.reflect.runtime.universe.TermSymbol = value x
scala> val fmX = im.reflectField(fieldX)
fmX: scala.reflect.runtime.universe.FieldMirror = field mirror for C.x (bound to C#5f0c8ac1)
scala> fmX.get
res0: Any = 2
Is there a way to do something like
val test: Int = fmX.get
That means can I "cast" the result of a reflection get to the actual type of the field? And otherwise: is it possible to do a reflection set from a string? In the example something like
fmx.set("10")
Thanks for hints!
Here's the deal... the type is not known at compile time, so, basically, you have to tell the compiler what the type it's supposed to be. You can do it safely or not, like this:
val test: Int = fmX.get.asInstanceOf[Int]
val test: Int = fmX.get match {
case n: Int => n
case _ => 0 // or however you want to handle the exception
}
Note that, since you declared test to be Int, you have to assign an Int to it. And even if you kept test as Any, at some point you have to pick a type for it, and it is always going to be something static -- as in, in the source code.
The second case just uses pattern matching to ensure you have the right type.
I'm not sure I understand what you mean by the second case.
I am using scalacheck and am in the middle of a generic-programming soup right now. The official guide shows this example:
def matrix[T](g: Gen[T]): Gen[Seq[Seq[T]]] = Gen.sized { size =>
val side = scala.math.sqrt(size).asInstanceOf[Int]
Gen.listOfN(side, Gen.listOfN(side, g))
}
Meanwhile, for my test I require a matrix of type Array[Array[T]]. I tried with the following function:
def matrix[T](g: Gen[T]): Gen[Array[Array[T]]] = Gen.sized { size =>
val side = scala.math.sqrt(size).asInstanceOf[Int]
val g1 = Gen.containerOfN[Array, T](side, g)
Gen.containerOfN[Array, Array[T]](side, g1)
}
Here, I run into trouble. The compiler says:
Multiple markers at this line
- not enough arguments for method containerOfN: (implicit b: org.scalacheck.util.Buildable[T,Array])org.scalacheck.Gen[Array[T]].
Unspecified value parameter b.
- could not find implicit value for parameter b: org.scalacheck.util.Buildable[T,Array]
- could not find implicit value for parameter b: org.scalacheck.util.Buildable[T,Array]
- not enough arguments for method containerOfN: (implicit b: org.scalacheck.util.Buildable[T,Array])org.scalacheck.Gen[Array[T]].
Unspecified value parameter b.
I understand that stuff like this is usually remedied by adding implicit parameters to the function, however, i havent made this work yet.
I usually encounter this error when building generic arrays, as an example:
def build[T](n:Int)(implicit m:ClassManifest[T]) = Array.ofDim[T](n)
but, I am afraid I don't fully understand what is happening or why this is needed.
Can someone explain how to make the correct matrix-function along with an example of usage in scalacheck? A thorough explanation of the details about building sequences with implicit class manifests would be very welcome!
edit
import org.scalacheck.util.Buildable._
def matrix[T](g: Gen[T])(implicit b: Buildable[T, Array]): Gen[Array[Array[T]]] = Gen.sized { size =>
val side = scala.math.sqrt(size).asInstanceOf[Int]
val g1 = Gen.containerOfN[Array, T](side, g)
Gen.containerOfN[Array, Array[T]](side, g1)
}
Still doesn't work. Need implicit for Buildable[Array[T],Array]... Don't know how to get this because I can only add 1 implicit argument :/
You're almost there. The important part of the error is could not find implicit value for parameter b: org.scalacheck.util.Buildable[T,Array]
Looking at the method definition of containerOfN
def containerOfN[C[_],T](n: Int, g: Gen[T])(implicit b: Buildable[T,C]): Gen[C[T]] = ...
So, there's your missing argument. You need an implicit argument of type Buildable[T,Array]. Following through to where Buildable is defined in the scalacheck sources, I found that there was an object (org.scalacheck.util.Buildable) that provides implicits that provide Buildables for the common collection types which includes Array. So all you need to bring that into scope. You can do this with:
import org.scalacheck.util.Buildable._
def matrix[T](g: Gen[T]): Gen[Array[Array[T]]] = Gen.sized { size =>
val bT = implicitly[Buildable[T, Array]]
val bArrayT = implicitly[Buildable[Array[T], Array]]
val side = scala.math.sqrt(size).asInstanceOf[Int]
val g1 = Gen.containerOfN[Array, T](side, g)
Gen.containerOfN[Array, Array[T]](side, g1)
}
Or
import org.scalacheck.util.Buildable._
def matrix[T](g: Gen[T])(implicit bT: Buildable[T, Array], bArrayT: Buildable[Array[T], Array]): Gen[Array[Array[T]]] = Gen.sized { size =>
...
}
The particular implicit you need in org.scalacheck.util.Buildable is:
implicit def buildableArray[T](implicit cm: ClassManifest[T]) =
new Buildable[T,Array] {
def builder = mutable.ArrayBuilder.make[T]
}
The scala code is simple:
case class X(id: Option[String] = None, username: Option[String])
object X {
def create(x: X): X = {
x.copy(id = Some("111"))
}
}
class Test {
def test() {
val x = X.create(X(
username = Some("Hello, world!")))
val id = x.id.get // !!! reports: recursive value x needs type
}
}
Please note the line:
val id = x.id.get
Why it reports recursive value x needs type?
If I change the variable name, as:
val dd = x.id.get
It will be OK.
PS: scala version is: 2.9.1.final
Removing the default argument for id in the definition of case class X also fixes the problem which suggests that this is an instance of SI-5091.
I am still in a process of figuring out the exact typing rules/implications involved in here.
It seems easy/easier if the types in the examples are "simple enough" to "fit well" as in almost all simple examples is the case, but it becomes more interresting/difficult (at least for me) in comparing things to the typing given by tiark rompf:
|- e: A#cpsParam[B,C]; {[|r|]}: U
-----------------------------------------------------
[|val x: A = e; r|] = [|e|].map( (x: A) => {[|r|]} )
so the result of [|e|].map( (x: A) => {[|r|]} ) will have the type Shift[U,B,C] according to the definition of map given in tiark's paper.
Here U is not necessarily the same as B.
So far I do not understand why U is allowed to be different from B without something like U <: B given in the definition of map in tiark's paper.
What am I missing respectively failing to understand here?
Any tips/ideas?
I had a second look at this as wanted to see what the result of the selective cps transform will yield in both cases.
U <: B
U is not a subtype of B
I used the following simple example:
package sample
import scala.util.continuations._
class Depp {
override def toString = "DEPP"
}
class Sepp extends Depp {
override def toString = "DEPP->SEPP"
}
object Sample extends Application {
val depp = new Depp
val sepp = new Sepp
val res = reset {
shift {
(k: Int => Depp) => k(7)
}
val z = sepp
z
}
println("Result = "+ res)
}
Compiling this using
scalac -P:continuations:enable -Xprint:selectivecps Sample.scala
proves successful and yields the following (interesting part only):
private[this] val res: sample.Depp = scala.util.continuations.package.reset[sample.Sepp, sample.Depp]({
package.this.shiftR[Int, sample.Depp, sample.Depp](((k: (Int) => sample.Depp) => k.apply(7))).map[sample.Sepp]
tmp1;
val z: sample.Sepp = Sample.this.sepp;
z
}))
ok so the type of the resulting (application of map) Shift object is [Sepp,Depp,Depp] as expected :)
which is fine because i understand how Shift objects like A#cpsParam[A,C] come into existence (the reset function given in Tiark's paper operates on such Shift objects)
Now changing the following in the simple example to yield a type unrelated to Depp: z.asInstanceOf[Float]
compiling this with
scalac -P:continuations:enable -Xprint:selectivecps -explaintypes Sample.scala
brings up the following error which tells what is actually checked:
Sample.scala:16: error: type mismatch;
found : Float #scala.util.continuations.cpsParam[sample.Depp,sample.Depp] #scala.util.continuations.cpsSynth
required: Float #scala.util.continuations.cpsParam[Float,sample.Depp]
val res = reset {
^
Float #scala.util.continuations.cpsParam[sample.Depp,sample.Depp] #scala.util.continuations.cpsSynth <: Float #scala.util.continuations.cpsParam[Float,sample.Depp]?
scala.util.continuations.cpsParam[sample.Depp,sample.Depp] <: scala.util.continuations.cpsParam[Float,sample.Depp]?
Float <: sample.Depp?
<notype> <: sample.Depp?
false
false
false
false
one error found
ahh and here is the test: Float <: sample.Depp?
so it fails because Float of course isn't a subtype of Depp
question: shouldn't the transformation rule then better be given as:
e: A#cpsParam[B,C] {[|r|]}: U U <: B
-----------------------------------------------------
[|val x: A = e; r|] = [|e|].map( (x: A) => {[|r|]} )
to clearly express this?