Given:
case class FirstCC {
def name: String = ... // something that will give "FirstCC"
}
case class SecondCC extends FirstCC
val one = FirstCC()
val two = SecondCC()
How can I get "FirstCC" from one.name and "SecondCC" from two.name?
def name = this.getClass.getName
Or if you want only the name without the package:
def name = this.getClass.getSimpleName
See the documentation of java.lang.Class for more information.
You can use the property productPrefix of the case class:
case class FirstCC {
def name = productPrefix
}
case class SecondCC extends FirstCC
val one = FirstCC()
val two = SecondCC()
one.name
two.name
N.B.
If you pass to scala 2.8 extending a case class have been deprecated, and you have to not forget the left and right parent ()
class Example {
private def className[A](a: A)(implicit m: Manifest[A]) = m.toString
override def toString = className(this)
}
def name = this.getClass.getName
Here is a Scala function that generates a human-readable string from any type, recursing on type parameters:
https://gist.github.com/erikerlandson/78d8c33419055b98d701
import scala.reflect.runtime.universe._
object TypeString {
// return a human-readable type string for type argument 'T'
// typeString[Int] returns "Int"
def typeString[T :TypeTag]: String = {
def work(t: Type): String = {
t match { case TypeRef(pre, sym, args) =>
val ss = sym.toString.stripPrefix("trait ").stripPrefix("class ").stripPrefix("type ")
val as = args.map(work)
if (ss.startsWith("Function")) {
val arity = args.length - 1
"(" + (as.take(arity).mkString(",")) + ")" + "=>" + as.drop(arity).head
} else {
if (args.length <= 0) ss else (ss + "[" + as.mkString(",") + "]")
}
}
}
work(typeOf[T])
}
// get the type string of an argument:
// typeString(2) returns "Int"
def typeString[T :TypeTag](x: T): String = typeString[T]
}
def name = getClass.getSimpleName.split('$').head
This will remove the $1 appearing at the end on some classes.
Related
suppose I have a util object with two function
object t {
def funA(input:String,x:Int):String = "hello"*x
def funB(input:String,tail:String):String = input + ":" + tail
}
if i run
funB(funA("x",3),"tail")
I get the result = xxx:tail
the question is how to design these two function then I can call them in a flow style like:
"x" funA(3) funB("tail")
Extend String, Using implicit class,
implicit class CustomString(str: String) {
def funcA(count:Int) = str * count
def funB(tail:String):String = str + ":" + tail
}
println("x".funcA(3).funB("tail"))
With a case class with a String field (corresponding to the original functions first argument),
case class StringOps(s: String) {
def funA(x:Int):String = s*x
def funB(tail:String):String = s + ":" + tail
}
and an implicit for converting String to StringOps,
implicit def String2StringOps(s: String) = StringOps(s)
you can enable the following usage,
scala> "hello" funA 3
hellohellohello
scala> "hello" funA 3 funB "tail"
hellohellohello:tail
If I have a class like this:
case class Key(
id: Long,
var text: String,
var `type`: String
)
Is there any way to get from that class the list of arguments like this:
['id', 'text', 'type']
If so, how would I do that? Thanks!
I don't know the solution for myself, but I found this on github:
https://gist.github.com/heathermiller/354befb88b097330d42d
import scala.reflect.runtime.universe._
class AbstractParams[T: TypeTag] {
def tag: TypeTag[T] = typeTag[T]
override def toString: String = {
// Find all case class fields in concrete class instance and print them as "[field name] [field value]"
val tag = this.tag
val tpe = tag.tpe
val allAccessors = tpe.declarations.collect { case meth: MethodSymbol if meth.isCaseAccessor => meth }
val m = runtimeMirror(getClass.getClassLoader)
val im = m.reflect(this)
val ctorArg2Strings = allAccessors map { sym =>
val fldMirror = im.reflectField(sym)
val value = fldMirror.get
"[" + sym.name + ": " + value + "]"
}
ctorArg2Strings.mkString(" ")
}
}
case class MyParams(id: String, stuff: Int) extends AbstractParams[MyParams]
object Ex extends App {
val p = new MyParams("joe", 2)
println(s"$p")
// prints:
// [id: joe] [stuff: 2]
}
I hope this might help.
I know that it's not exactly what you was looking for, but you can adjust this solution for yourself.
I'm trying to implement an implicit materializer as described here: http://docs.scala-lang.org/overviews/macros/implicits.html
I decided to create a macro that converts a case class from and to a String using quasiquotes for prototyping purposes. For example:
case class User(id: String, name: String)
val foo = User("testid", "foo")
Converting foo to text should result in "testid foo" and vice versa.
Here is the simple trait and its companion object I have created:
trait TextConvertible[T] {
def convertTo(obj: T): String
def convertFrom(text: String): T
}
object TextConvertible {
import language.experimental.macros
import QuasiTest.materializeTextConvertible_impl
implicit def materializeTextConvertible[T]: TextConvertible[T] = macro materializeTextConvertible_impl[T]
}
and here is the macro:
object QuasiTest {
import reflect.macros._
def materializeTextConvertible_impl[T: c.WeakTypeTag](c: Context): c.Expr[TextConvertible[T]] = {
import c.universe._
val tpe = weakTypeOf[T]
val fields = tpe.declarations.collect {
case field if field.isMethod && field.asMethod.isCaseAccessor => field.asMethod.accessed
}
val strConvertTo = fields.map {
field => q"obj.$field"
}.reduce[Tree] {
case (acc, elem) => q"""$acc + " " + $elem"""
}
val strConvertFrom = fields.zipWithIndex map {
case (field, index) => q"splitted($index)"
}
val quasi = q"""
new TextConvertible[$tpe] {
def convertTo(obj: $tpe) = $strConvertTo
def convertFrom(text: String) = {
val splitted = text.split(" ")
new $tpe(..$strConvertFrom)
}
}
"""
c.Expr[TextConvertible[T]](quasi)
}
}
which generates
{
final class $anon extends TextConvertible[User] {
def <init>() = {
super.<init>();
()
};
def convertTo(obj: User) = obj.id.$plus(" ").$plus(obj.name);
def convertFrom(text: String) = {
val splitted = text.split(" ");
new User(splitted(0), splitted(1))
}
};
new $anon()
}
The generated code looks fine, but yet I get the error value id in class User cannot be accessed in User in compilation while trying to use the macro.
I suspect I am using a wrong type for fields. I tried field.asMethod.accessed.name, but it results in def convertTo(obj: User) = obj.id .$plus(" ").$plus(obj.name ); (note the extra spaces after id and name), which naturally results in the error value id is not a member of User.
What am I doing wrong?
Ah, figured it out almost immediately after sending my question.
I changed the lines
val fields = tpe.declarations.collect {
case field if field.isMethod && field.asMethod.isCaseAccessor => field.asMethod.accessed
}
to
val fields = tpe.declarations.collect {
case field if field.isMethod && field.asMethod.isCaseAccessor => field.name
}
which solved the problem.
The field you get with accessed.name has a special suffix attached to it, to avoid naming conflicts.
The special suffix is scala.reflect.api.StandardNames$TermNamesApi.LOCAL_SUFFIX_STRING, which has the value, you guessed it, a space char.
This is quite evil, of course.
from time to time, i deal with java that has stuff like the following in it:
def printDbl(d:Double) { println("dbl: " + d) }
def printInt(i:Int) { println("int: " + i) }
naturally, i'd like to wrap this in some scala, which ends up looking like this:
def print[T:Manifest] (t:T) {
if (manifest[T] <:< manifest[Int]) { printInt(t.asInstanceOf[Int]) ; return }
if (manifest[T] <:< manifest[Double]) { printDbl(t.asInstanceOf[Double]) ; return }
throw new UnsupportedOperationException("not implemented: " + manifest[T])
}
but when i run the following, i get a runtime exception:
print(1)
print(2.0)
print("hello")
i seem to recall there being a way to catch this at compile time, but i can't seem to google it up. perhaps some clever implied conversions?
Why don't you just take advantage of method overloading and write your Scala wrapper like this?:
object Printer {
def print(d: Double) { printDbl(d) }
def print(i: Int) { printInt(i) }
}
This is very simple and provides the desired behavior:
import Printer._
print(1.) // dbl: 1.0
print(1) // int: 1
print("hello") // compile-time type error
scala> object SpecType {
| trait SpecType[T] {
| def is(s: String): Boolean
| }
| implicit object DoubleType extends SpecType[Double] {
| def is(s: String) = s == "Double"
| }
| implicit object IntType extends SpecType[Int] {
| def is(s: String) = s == "Int"
| }
| }
defined module SpecType
scala> import SpecType._
import SpecType._
scala> def print[T: SpecType](x: T) {
| if(implicitly[SpecType[T]].is("Int")) println("Int")
| if(implicitly[SpecType[T]].is("Double")) println("Double")
| }
print: [T](x: T)(implicit evidence$1: SpecType.SpecType[T])Unit
scala> print(1)
Int
scala> print(1.0)
Double
scala> print("")
<console>:21: error: could not find implicit value for evidence parameter of typ
e SpecType.SpecType[String]
print("")
this is the best i've come up with
class CanPrint[T] (t:T) { def getT = t}
implicit def canPrint(i:Int) = new CanPrint[Int](i)
implicit def canPrint(d:Double) = new CanPrint[Double](d)
def print[T:Manifest] (t:CanPrint[T]) {
if (manifest[T] <:< manifest[Int]) { printInt(t.getT.asInstanceOf[Int]) ; return }
if (manifest[T] <:< manifest[Double]) { printDbl(t.getT.asInstanceOf[Double]) ; return }
throw new UnsupportedOperationException("not implemented: " + manifest[T])
}
the following does not compile
print(1)
print(1.0)
print("hello")
and the following does what i expect
print(1)
print(1.0)
however, this is bad code because i have to import the implicit defs for it to work, and as a consumer of this code all i see is the method signature saying that i have to pass in a CanPrint object, which i can instantiate.
print(new CanPrint("hello")) // pwned
can i make the constructor private and only accessible to the implicit methods or some such?
def printDbl(d:Double) { println("dbl: " + d) }
def printInt(i:Int) { println("int: " + i) }
trait Printer[T] { def print(t:T) }
class PD extends Printer[Double] { def print(d:Double) = printDbl(d) }
class PI extends Printer[Int] { def print(i:Int) = printInt(i) }
implicit val pd = new PD()
implicit val pi = new PI()
def print[T](t:T)(implicit printer:Printer[T]) = printer.print(t)
print(1) // 1
print(2.0) // 2.0
print("hello") // Error:(88, 7) could not find implicit value for parameter printer: A$A336.this.Printer[String]
With Scala's pattern matching I would like to confirm not only that two Strings are equal but for example, whether a String starts with, ends, or is contained in another etc.
I experimented with case classes and extractor objects, neither giving me a concise solution. So the solution I came up with looks like the following:
class StrMatches(private val str: Option[String]) {
def ^(prefix: String) = str.exists(_.startsWith(prefix))
def §(suffix: String) = str.exists(_.endsWith(suffix))
def %(infix: String) = str.exists(_.contains(infix))
def ~(approx: String) = str.exists(_.equalsIgnoreCase(approx))
def /(regex: scala.util.matching.Regex) = str.collect({ case regex() => true }).isDefined
def °(len: Int) = str.exists(_.length == len)
def °°(len: (Int, Int)) = str.exists(a => a.length >= len._1 && a.length <= len._2)
def `\\s*` = str.exists(_.trim.isEmpty)
override def toString = str.mkString
}
object StrMatches {
implicit def apply(x: Str) = new StrMatches(x)
def unapply(x: StrMatches) = x.str
implicit def unwrap(x: StrMatches) = x.toString
}
A client using the StrMatches class could look like the following:
object TestApp extends App {
val str = "foobar"
val strMatches = StrMatches(str)
if (strMatches ^ "foo") {
println(strMatches)
}
if (strMatches § "bar") {
println(strMatches)
}
if (strMatches % "ob") {
println(strMatches)
}
}
As opposed to writing:
object TestApp extends App {
val str: String = null // Just as an illustration for Scala interfacing Java.
if (str != null) {
if (str.startsWith("foo")) {
println(str)
}
if (strMatches.endsWith("bar")) {
println(str)
}
if (strMatches.contains("ob")) {
println(strMatches)
}
}
}
With what kind of solutions would you come up with?
You could use regular expressions. Then you could use pattern matching (which I think was the original intent of your question):
object TestApp extends App {
val str = "foobar"
val StartsWithFooRE = """^foo.*""".r
val EndsWithBarRE = """.*bar$""".r
val ContainsBoRE = """.*bo.*""".r
str match {
case StartsWithFooRE() => println(str)
case EndsWithBarRE() => println(str)
case ContainsBoRE() => println(str)
case _ =>
}
}
To make this more convenient, you could define an object with factory methods to construct the regular expressions. However, due to how pattern matching works, you'll still have to define the expressions outside of the match:
import scala.util.matching.Regex
object RegexFactory {
def startsWith(str: String) = new Regex("^%s.*" format str)
def endsWith(str: String) = new Regex(".*%s$" format str)
def contains(str: String) = new Regex(".*%s.*" format str)
}
object TestApp extends App {
val str = "foobar"
import RegexFactory._
val StartsWithFooRE = startsWith("foo")
val EndsWithBarRE = endsWith("bar")
val ContainsBoRE = contains("bo")
str match {
case StartsWithFooRE() => println(str)
case EndsWithBarRE() => println(str)
case ContainsBoRE() => println(str)
case _ =>
}
}