In a scala macro, how to get the full name that a class will have at runtime? - scala

The intention is to get at run-time some info of particular classes that is available only at compile-time.
My approach was to generate the info at compile time with a macro that expands to a map that contains the info indexed by the runtime class name.
Something like this:
object macros {
def subClassesOf[T]: Map[String, Info] = macro subClassesOfImpl[T];
def subClassesOfImpl[T: ctx.WeakTypeTag](ctx: blackbox.Context): ctx.Expr[Map[String, Info]] = {
import ctx.universe._
val classSymbol = ctx.weakTypeTag[T].tpe.typeSymbol.asClass
val addEntry_codeLines: List[Tree] =
for {baseClassSymbol <- classSymbol.knownDirectSubclasses.toList} yield {
val key = baseClassSymbol.asType.toType.erasure.typeSymbol.fullName
q"""builder.addOne($key -> new Info("some info"));"""
}
q"""
val builder = Map.newBuilder[String, Info];
{..$addEntry_codeLines}
builder.result();""";
ctx.Expr[Map[String, Info]](body_code);
}
}
Which would we used like this:
object shapes {
trait Shape;
case class Box(h: Int, w: Int);
case class Sphere(r: Int);
}
val infoMap = subclassesOf[shapes.Shape];
val box = Box(3, 7);
val infoOfBox = infoMap.get(box.getClass.getName)
The problem is that the names of the erased classes given by that macro are slightly different from the ones obtained at runtime by the someInstance.getClass.getName method. The first uses dots to separate container from members, and the second uses dollars.
scala> infoMap.mkString("\n")
val res7: String =
shapes.Box -> Info(some info)
shapes.Sphere -> Info(some info)
scala> box.getClass.getName
val res8: String = shapes$Box
How is the correct way to obtain at compile time the name that a class will have at runtime?

Vice versa, at runtime, having Java name of a class (with dollars) you can obtain Scala name (with dots).
box.getClass.getName
// com.example.App$shapes$Box
import scala.reflect.runtime
val runtimeMirror = runtime.currentMirror
runtimeMirror.classSymbol(box.getClass).fullName // com.example.App.shapes.Box
This can be done even with replace
val nameWithDot = box.getClass.getName.replace('$', '.')
if (nameWithDot.endsWith(".")) nameWithDot.init else nameWithDot
// com.example.App.shapes.Box
Anyway, at compile time you can try
def javaName[T]: String = macro javaNameImpl[T]
def javaNameImpl[T: ctx.WeakTypeTag](ctx: blackbox.Context): ctx.Expr[String] = {
import ctx.universe._
val symbol = weakTypeOf[T].typeSymbol
val owners = Seq.unfold(symbol)(symb =>
if (symb != ctx.mirror.RootClass) Some((symb, symb.owner)) else None
)
val nameWithDollar = owners.foldRight("")((symb, str) => {
val sep = if (symb.isPackage) "." else "$"
s"$str${symb.name}$sep"
})
val name = if (symbol.isModuleClass) nameWithDollar else nameWithDollar.init
ctx.Expr[String](q"${name: String}")
}
javaName[shapes.Shape] // com.example.App$shapes$Shape
One more option is to use runtime reflection inside a macro. Replace
val key = baseClassSymbol.asType.toType.erasure.typeSymbol.fullName
with
val key = javaName(baseClassSymbol.asType.toType.erasure.typeSymbol.asClass)
where
def subClassesOfImpl[T: ctx.WeakTypeTag](ctx: blackbox.Context): ctx.Expr[Map[String, Info]] = {
import ctx.universe._
def javaName(symb: ClassSymbol): String = {
val rm = scala.reflect.runtime.currentMirror
rm.runtimeClass(symb.asInstanceOf[scala.reflect.runtime.universe.ClassSymbol]).getName
}
...
}
This works only with classes existing at compile time. So the project should be organized as follows
subproject common. Shape, Box, Sphere
subproject macros (depends on common). def subClassesOf...
subproject core (depends on macros and common). subclassesOf[shapes.Shape]...

The answer from #Dmytro_Mitin helped me to notice that the scala reflect API does not offer a fast one line method to get the name that a class will have at runtime, and guided me solve my particular problem in another way.
If what you need to know is not the run-time class name itself but only if it matches the name accesible at compile-time, efficiently, then this answer may be useful.
Instead of figuring out what the name will be at runtime, which is apparently not possible before knowing all the classes; just find out if the name we know at compile time corresponds or not to one obtained at runtime.
This can be achieved with a string comparator that considers the relevant character and ignores whatever the compiler appends later.
/** Compares two class names based on the length and, if both have the same length, by alphabetic order of the reversed names.
* If the second name (`b`) ends with a dollar, or a dollar followed by digits, they are removed before the comparison begins. This is necessary because the runtime class name of: module classes have an extra dollar at the end, local classes have a dollar followed by digits, and local object digits surrounded by dollars.
* Differences between dots and dollars are ignored if the dot is in the first name (`a`) and the dollar in the second name (`b`). This is necessary because the runtime class name of nested classes use a dollar instead of a dot to separate the container from members.
* The names are considered equal if the fragments after the last dot of the second name (`b`) are equal. */
val productNameComparator: Comparator[String] = { (a, b) =>
val aLength = a.length;
var bLength = b.length;
var bChar: Char = 0;
var index: Int = 0;
// Ignore the last segment of `b` if it matches "(\$\d*)+". This is necessary because the runtime class name of: module classes have an extra dollar at the end, local classes have a dollar followed by a number, and local object have a number surrounded by dollars.
// Optimized versiĆ³n
var continue = false;
do {
index = bLength - 1;
continue = false;
// find the index of the last non digit character
while ( {bChar = b.charAt(index); Character.isDigit(bChar)}) {
index -= 1;
}
// if the index of the last non digit character is a dollar, remove it along with the succeeding digits for the comparison.
if (b.charAt(index) == '$') {
bLength = index;
// if something was removed, repeat the process again to support combinations of edge cases. It is not necessary to know all the edge cases if it's known that any dollar or dollar followed by digits at the end are not part of the original class name. So we can remove combinations of them without fear.
continue = true;
}
} while(continue)
// here starts the comparison
var diff = aLength - bLength;
if (diff == 0 && aLength > 0) {
index = aLength - 1;
do {
val aChar = a.charAt(index);
bChar = b.charAt(index);
diff = if (aChar == '.' && bChar == '$') {
0 // Ignore difference between dots and dollars. This assumes that the first name (an) is obtained by the macro, and the second (bn) may be obtained at runtime from the Class object.
} else {
aChar - bChar;
}
index -= 1;
} while (diff == 0 && index >= 0 && bChar != '.')
}
diff
}
Note that it is designed to compare names of classes that extend the same sealed trait or abstract class. Which means that the names may differ only after the last dot.
Also note that the first argument only supports a compile time name (only dots), while the second supports both, a compile-time or a run-time name.

Related

Why does a Scalacheck Prop value not get evaluated?

The official scalacheck documentation gives the following example:
property("stringLength") = Prop.forAll { s: String =>
val len = s.length
(s+s).length == len+len
}
I read that this can also be written as:
val stringLength = Prop.forAll { s: String =>
val len = s.length
(s+s).length == len+len
}
How can I run the second form of test code? When I execute sbt test, nothing happens with the second version.
The problem is that the second version is simply declaring a val that holds a reference to the property in question but that isn't enough to get scalacheck to evaluate it. This style of declaring a property is useful for example if you want to compose a new property out of other basic properties. You can check it directly or to assign it the special property setter in order to get it to be evaluated as part of the test run:
val stringLength = Prop.forAll { s: String =>
val len = s.length
(s+s).length == len+len
}
// invoke directly:
stringLength.check
// alternatively, just declare it the usual way
property("stringLength") = stringLength
This isn't very useful by itself, the way it is meant to be used is perhaps something like this:
property("composite") = Prop.all(stringLength, prop2, prop3, ...)

How to declare packages with Quasiquotes

I am trying to use quasi quote to generate the package AST. I have a string variable that lists out the package path such that
val pkg = "database.dao"
When I use quasi quote q"package $pkg, it tells me that I need a RefTree instead. I tried searching for a while now and still haven't found an answer to convert the string to RefTree
How do I do so?
I found the answer on pg 7 of this slideshare
It turns out I will need to generate my own AST using multiple Select()s if I want to dynamically inject the package variable.
def selectIdentity(directory: String): Select = {
val dirs = directory.split('.').reverse
val lastIndex = dirs.length - 1
def apply(i: Int = 0) : Select = if (i < lastIndex - 1) {
Select(apply(i + 1), TermName(dirs(i)))
} else {
Select(Ident(TermName(dirs(lastIndex))), TermName(dirs(lastIndex - 1)))
}
apply()
}

How to read input from a file and convert data lines of the file to List[Map[Int,String]] using scala?

My Query is, read input from a file and convert data lines of the file to List[Map[Int,String]] using scala. Here I give a dataset as the input. My code is,
def id3(attrs: Attributes,
examples: List[Example],
label: Symbol
) : Node = {
level = level+1
// if all the examples have the same label, return a new node with that label
if(examples.forall( x => x(label) == examples(0)(label))){
new Leaf(examples(0)(label))
} else {
for(a <- attrs.keySet-label){ //except label, take all attrs
("Information gain for %s is %f".format(a,
informationGain(a,attrs,examples,label)))
}
// find the best splitting attribute - this is an argmax on a function over the list
var bestAttr:Symbol = argmax(attrs.keySet-label, (x:Symbol) =>
informationGain(x,attrs,examples,label))
// now we produce a new branch, which splits on that node, and recurse down the nodes.
var branch = new Branch(bestAttr)
for(v <- attrs(bestAttr)){
val subset = examples.filter(x=> x(bestAttr)==v)
if(subset.size == 0){
// println(levstr+"Tiny subset!")
// zero subset, we replace with a leaf labelled with the most common label in
// the examples
val m = examples.map(_(label))
val mostCommonLabel = m.toSet.map((x:Symbol) => (x,m.count(_==x))).maxBy(_._2)._1
branch.add(v,new Leaf(mostCommonLabel))
}
else {
// println(levstr+"Branch on %s=%s!".format(bestAttr,v))
branch.add(v,id3(attrs,subset,label))
}
}
level = level-1
branch
}
}
}
object samplet {
def main(args: Array[String]){
var attrs: sample.Attributes = Map()
attrs += ('0 -> Set('abc,'nbv,'zxc))
attrs += ('1 -> Set('def,'ftr,'tyh))
attrs += ('2 -> Set('ghi,'azxc))
attrs += ('3 -> Set('jkl,'fds))
attrs += ('4 -> Set('mno,'nbh))
val examples: List[sample.Example] = List(
Map(
'0 -> 'abc,
'1 -> 'def,
'2 -> 'ghi,
'3 'jkl,
'4 -> 'mno
),
........................
)
// obviously we can't use the label as an attribute, that would be silly!
val label = 'play
println(sample.try(attrs,examples,label).getStr(0))
}
}
But How I change this code to - accepting input from a .csv file?
I suggest you use Java's io / nio standard library to read your CSV file. I think there is no relevant drawback in doing so.
But the first question we need to answer is where to read the file in the code? The parsed input seems to replace the value of examples. This fact also hints us what type the parsed CSV input must have, namely List[Map[Symbol, Symbol]]. So let us declare a new class
class InputFromCsvLoader(charset: Charset = Charset.defaultCharset()) {
def getInput(file: Path): List[Map[Symbol, Symbol]] = ???
}
Note that the Charset is only needed if we must distinguish between differently encoded CSV-files.
Okay, so how do we implement the method? It should do the following:
Create an appropriate input reader
Read all lines
Split each line at the comma-separator
Transform each substring into the symbol it represents
Build a map from from the list of symbols, using the attributes as key
Create and return the list of maps
Or expressed in code:
class InputFromCsvLoader(charset: Charset = Charset.defaultCharset()) {
val Attributes = List('outlook, 'temperature, 'humidity, 'wind, 'play)
val Separator = ","
/** Get the desired input from the CSV file. Does not perform any checks, i.e., there are no guarantees on what happens if the input is malformed. */
def getInput(file: Path): List[Map[Symbol, Symbol]] = {
val reader = Files.newBufferedReader(file, charset)
/* Read the whole file and discard the first line */
inputWithHeader(reader).tail
}
/** Reads all lines in the CSV file using [[java.io.BufferedReader]] There are many ways to do this and this is probably not the prettiest. */
private def inputWithHeader(reader: BufferedReader): List[Map[Symbol, Symbol]] = {
(JavaConversions.asScalaIterator(reader.lines().iterator()) foldLeft Nil.asInstanceOf[List[Map[Symbol, Symbol]]]){
(accumulator, nextLine) =>
parseLine(nextLine) :: accumulator
}.reverse
}
/** Parse an entry. Does not verify the input: If there are less attributes than columns or vice versa, zip creates a list of the size of the shorter list */
private def parseLine(line: String): Map[Symbol, Symbol] = (Attributes zip (line split Separator map parseSymbol)).toMap
/** Create a symbol from a String... we could also check whether the string represents a valid symbol */
private def parseSymbol(symbolAsString: String): Symbol = Symbol(symbolAsString)
}
Caveat: Expecting only valid input, we are certain that the individual symbol representations do not contain the comma-separation character. If this cannot be assumed, then the code as is would fail to split certain valid input strings.
To use this new code, we could change the main-method as follows:
def main(args: Array[String]){
val csvInputFile: Option[Path] = args.headOption map (p => Paths get p)
val examples = (csvInputFile map new InputFromCsvLoader().getInput).getOrElse(exampleInput)
// ... your code
Here, examples uses the value exampleInput, which is the current, hardcoded value of examples if no input argument is specified.
Important: In the code, all error handling has been omitted for convenience. In most cases, errors can occur when reading from files and user input must be considered invalid, so sadly, error handling at the boundaries of your program is usally not optional.
Side-notes:
Try not to use null in your code. Returning Option[T] is a better option than returning null, because it makes "nullness" explicit and provides static safety thanks to the type-system.
The return-keyword is not required in Scala, as the last value of a method is always returned. You can still use the keyword if you find the code more readable or if you want to break in the middle of your method (which is usually a bad idea).
Prefer val over var, because immutable values are much easier to understand than mutable values.
The code will fail with the provided CSV string, because it contains the symbols TRUE and FALSE which are not legal according to your programs logic (they should be true and false instead).
Add all information to your error-messages. Your error message only tells me what that a value for the attribute 'wind is bad, but it does not tell me what the actual value is.
Read a csv file ,
val datalines = Source.fromFile(filepath).getLines()
So this datalines contains all the lines from the csv file.
Next, convert each line into a Map[Int,String]
val datamap = datalines.map{ line =>
line.split(",").zipWithIndex.map{ case (word, idx) => idx -> word}.toMap
}
Here, we split each line with ",". Then construct a map with key as column number and value as each word after the split.
Next, If we want List[Map[Int,String]],
val datamap = datalines.map{ line =>
line.split(",").zipWithIndex.map{ case (word, idx) => idx -> word}.toMap
}.toList

Access code file and line number from Scala macro?

How can I access the name of the code file and line number in a Scala macro? I looked at SIP-19 and it says it can be easily implemented using macros...
EDIT:
To clarify, I want the code file and line number of the caller. I already have a debug macro and I want to modify it to print the line number and file name of whoever calls debug
You want c.macroApplication.pos, where c is for Context.
c.enclosingPosition finds the nearest macro on the stack that has a position. (See the other answer.) For instance, if your assert macro generates a tree for F"%p: $msg" but doesn't assign a position, the F macro would be positionless.
Example from a string interpolator macro, F"%p":
/* Convert enhanced conversions to something format likes.
* %Q for quotes, %p for position, %Pf for file, %Pn line number,
* %Pc column %Po offset.
*/
private def downConvert(parts: List[Tree]): List[Tree] = {
def fixup(t: Tree): Tree = {
val Literal(Constant(s: String)) = t
val r = "(?<!%)%(p|Q|Pf|Po|Pn|Pc)".r
def p = c.macroApplication.pos
def f(m: Match): String = m group 1 match {
case "p" => p.toString
case "Pf" => p.source.file.name
case "Po" => p.point.toString
case "Pn" => p.line.toString
case "Pc" => p.column.toString
case "Q" => "\""
}
val z = r.replaceAllIn(s, f _)
Literal(Constant(z)) //setPos t.pos
}
parts map fixup
}
If you mean file name and line number of the current position in the source code, for 2.10, my answer to that SO question is what your looking for:
def $currentPosition:String = macro _currentPosition
def _currentPosition(c:Context):c.Expr[String]={ import c.universe._
val pos = c.enclosingPosition
c.Expr(Literal(Constant(s"${pos.source.path}: line ${pos.line}, column ${pos.column}")))
}
That should work with 2.11 as well, although this way of creating the AST seems deprecated.
You can also have a look at that excerpt of my project Scart; it's how I use this technique to emit traces for debugging purposes.
The example in 'Writing Scala Compiler Plugins' shows how to access the line name and current number of the current position, as the others answers have mentioned.
http://www.scala-lang.org/old/node/140
In addition to the answers above, you can also get the position from the AST returned from a CompilationUnit.
For example:
def apply(unit: CompilationUnit) {
// Get the AST
val tree = unit.body
// Get the Position
// Scala.util.parsing.input.Position
val myPos = tree.pos
// Do something with the pos
unit.warning(pos, "Hello world")
}

Increment (++) operator in Scala

Is there any reason for Scala not support the ++ operator to increment primitive types by default?
For example, you can not write:
var i=0
i++
Thanks
My guess is this was omitted because it would only work for mutable variables, and it would not make sense for immutable values. Perhaps it was decided that the ++ operator doesn't scream assignment, so including it may lead to mistakes with regard to whether or not you are mutating the variable.
I feel that something like this is safe to do (on one line):
i++
but this would be a bad practice (in any language):
var x = i++
You don't want to mix assignment statements and side effects/mutation.
I like Craig's answer, but I think the point has to be more strongly made.
There are no "primitives" -- if Int can do it, then so can a user-made Complex (for example).
Basic usage of ++ would be like this:
var x = 1 // or Complex(1, 0)
x++
How do you implement ++ in class Complex? Assuming that, like Int, the object is immutable, then the ++ method needs to return a new object, but that new object has to be assigned.
It would require a new language feature. For instance, let's say we create an assign keyword. The type signature would need to be changed as well, to indicate that ++ is not returning a Complex, but assigning it to whatever field is holding the present object. In Scala spirit of not intruding in the programmers namespace, let's say we do that by prefixing the type with #.
Then it could be like this:
case class Complex(real: Double = 0, imaginary: Double = 0) {
def ++: #Complex = {
assign copy(real = real + 1)
// instead of return copy(real = real + 1)
}
The next problem is that postfix operators suck with Scala rules. For instance:
def inc(x: Int) = {
x++
x
}
Because of Scala rules, that is the same thing as:
def inc(x: Int) = { x ++ x }
Which wasn't the intent. Now, Scala privileges a flowing style: obj method param method param method param .... That mixes well C++/Java traditional syntax of object method parameter with functional programming concept of pipelining an input through multiple functions to get the end result. This style has been recently called "fluent interfaces" as well.
The problem is that, by privileging that style, it cripples postfix operators (and prefix ones, but Scala barely has them anyway). So, in the end, Scala would have to make big changes, and it would be able to measure up to the elegance of C/Java's increment and decrement operators anyway -- unless it really departed from the kind of thing it does support.
In Scala, ++ is a valid method, and no method implies assignment. Only = can do that.
A longer answer is that languages like C++ and Java treat ++ specially, and Scala treats = specially, and in an inconsistent way.
In Scala when you write i += 1 the compiler first looks for a method called += on the Int. It's not there so next it does it's magic on = and tries to compile the line as if it read i = i + 1. If you write i++ then Scala will call the method ++ on i and assign the result to... nothing. Because only = means assignment. You could write i ++= 1 but that kind of defeats the purpose.
The fact that Scala supports method names like += is already controversial and some people think it's operator overloading. They could have added special behavior for ++ but then it would no longer be a valid method name (like =) and it would be one more thing to remember.
I think the reasoning in part is that +=1 is only one more character, and ++ is used pretty heavily in the collections code for concatenation. So it keeps the code cleaner.
Also, Scala encourages immutable variables, and ++ is intrinsically a mutating operation. If you require +=, at least you can force all your mutations to go through a common assignment procedure (e.g. def a_=).
The primary reason is that there is not the need in Scala, as in C. In C you are constantly:
for(i = 0, i < 10; i++)
{
//Do stuff
}
C++ has added higher level methods for avoiding for explicit loops, but Scala has much gone further providing foreach, map, flatMap foldLeft etc. Even if you actually want to operate on a sequence of Integers rather than just cycling though a collection of non integer objects, you can use Scala range.
(1 to 5) map (_ * 3) //Vector(3, 6, 9, 12, 15)
(1 to 10 by 3) map (_ + 5)//Vector(6, 9, 12, 15)
Because the ++ operator is used by the collection library, I feel its better to avoid its use in non collection classes. I used to use ++ as a value returning method in my Util package package object as so:
implicit class RichInt2(n: Int)
{
def isOdd: Boolean = if (n % 2 == 1) true else false
def isEven: Boolean = if (n % 2 == 0) true else false
def ++ : Int = n + 1
def -- : Int = n - 1
}
But I removed it. Most of the times when I have used ++ or + 1 on an integer, I have later found a better way, which doesn't require it.
It is possible if you define you own class which can simulate the desired output however it may be a pain if you want to use normal "Int" methods as well since you would have to always use *()
import scala.language.postfixOps //otherwise it will throw warning when trying to do num++
/*
* my custom int class which can do ++ and --
*/
class int(value: Int) {
var mValue = value
//Post-increment
def ++(): int = {
val toReturn = new int(mValue)
mValue += 1
return toReturn
}
//Post-decrement
def --(): int = {
val toReturn = new int(mValue)
mValue -= 1
return toReturn
}
//a readable toString
override def toString(): String = {
return mValue.toString
}
}
//Pre-increment
def ++(n: int): int = {
n.mValue += 1
return n;
}
//Pre-decrement
def --(n: int): int = {
n.mValue -= 1
return n;
}
//Something to get normal Int
def *(n: int): Int = {
return n.mValue
}
Some possible test cases
scala>var num = new int(4)
num: int = 4
scala>num++
res0: int = 4
scala>num
res1: int = 5 // it works although scala always makes new resources
scala>++(num) //parentheses are required
res2: int = 6
scala>num
res3: int = 6
scala>++(num)++ //complex function
res4: int = 7
scala>num
res5: int = 8
scala>*(num) + *(num) //testing operator_*
res6: Int = 16
Of course you can have that in Scala, if you really want:
import scalaz._
import Scalaz._
case class IncLens[S,N](lens: Lens[S,N], num : Numeric[N]) {
def ++ = lens.mods(num.plus(_, num.one))
}
implicit def incLens[S,N:Numeric](lens: Lens[S,N]) =
IncLens[S,N](lens, implicitly[Numeric[N]])
val i = Lens[Int,Int](identity, (x, y) => y)
val imperativeProgram = for {
_ <- i := 0;
_ <- i++;
_ <- i++;
x <- i++
} yield x
def runProgram = imperativeProgram ! 0
And here you go:
scala> runProgram
runProgram: Int = 3
It isn't included because Scala developers thought it make the specification more complex while achieving only negligible benefits and because Scala doesn't have operators at all.
You could write your own one like this:
class PlusPlusInt(i: Int){
def ++ = i+1
}
implicit def int2PlusPlusInt(i: Int) = new PlusPlusInt(i)
val a = 5++
// a is 6
But I'm sure you will get into some trouble with precedence not working as you expect. Additionally if i++ would be added, people would ask for ++i too, which doesn't really fit into Scala's syntax.
Lets define a var:
var i = 0
++i is already short enough:
{i+=1;i}
Now i++ can look like this:
i(i+=1)
To use above syntax, define somewhere inside a package object, and then import:
class IntPostOp(val i: Int) { def apply(op: Unit) = { op; i } }
implicit def int2IntPostOp(i: Int): IntPostOp = new IntPostOp(i)
Operators chaining is also possible:
i(i+=1)(i%=array.size)(i&=3)
The above example is similar to this Java (C++?) code:
i=(i=i++ %array.length)&3;
The style could depend, of course.