I have a high level structure of my code as follows. This is just an example replicating the high level structure.:-
import scala.concurrent.Future
class FutureReturnsAValue extends PersonAgeModifier {
def main(args: Array[String]) {
val jhonObj = Person("Jhon", 25)
val punishmentResult = addAgeCurse(jhonObj)
println("The punishment result for Jhonny is " + punishmentResult)
}
def addAgeCurse(person: Person): String = {
val oldAge = person.age
val futureAge = LongProcessingOpForAge(person)
futureAge.onSuccess {
newAge =>
if (newAge = oldAge + 5) {
"screw the kiddo, he aged by 5 years" // somehow return this string
}
else {
"lucky chap, the spell did not affect him" // somehow return this string
}
}
}
}
class PersonAgeModifier {
def LongProcessingOpForAge(person: Person): Future[Int] = {
Future.successful {
person.age + 5
}
}
}
case class Person
(
val name: String,
var age: Int
)
object Person {
def apply(name: String, age: Int) = new Person(name, age)
}
So my requirement is this:- I need the string from the addAgeCurse() method. Now I know some off you may suggest to pass the future value LongProcessingOpForAge() as such to main() but that is not what I want here.
Questions:
What is the cleanest way to obtain the string and pass it to main(). ( By clean , I mean something which does not involve using wait for x duration as I would like to avoid any manual intervention.)
Thanks
Maybe you're asking for:
scala> import concurrent._, ExecutionContext.Implicits._
import concurrent._
import ExecutionContext.Implicits._
scala> def f = Future(42)
f: scala.concurrent.Future[Int]
scala> def g = f.map(_ + 1)
g: scala.concurrent.Future[Int]
scala> :pa
// Entering paste mode (ctrl-D to finish)
object Main extends App {
for (i <- g) println(i)
}
// Exiting paste mode, now interpreting.
defined object Main
scala> Main main null
43
That's the easy idiom to block for your answer. The main thread won't exit until it has it. Use map to transform a future value.
Related
I need to implement a testing function which checks compile-time error information for the "splain" plugin, part of this function needs to convert a codeblock into a string, e.g.:
def convert(fn: => Unit): String
// for testing
val code = convert {
object I extends Seq {}
}
assert(code == "object I extends Seq {}")
Is this possible using standard scala features? Thanks a lot for your advice.
This function will enable verifications of compile-time messages of complex code that needs to be indexed and refactored by IDE often
Yes, it's possible.
Li Haoyi's macro Text from sourcecode
def text[T: c.WeakTypeTag](c: Compat.Context)(v: c.Expr[T]): c.Expr[sourcecode.Text[T]] = {
import c.universe._
val fileContent = new String(v.tree.pos.source.content)
val start = v.tree.collect {
case treeVal => treeVal.pos match {
case NoPosition ⇒ Int.MaxValue
case p ⇒ p.startOrPoint
}
}.min
val g = c.asInstanceOf[reflect.macros.runtime.Context].global
val parser = g.newUnitParser(fileContent.drop(start))
parser.expr()
val end = parser.in.lastOffset
val txt = fileContent.slice(start, start + end)
val tree = q"""${c.prefix}(${v.tree}, $txt)"""
c.Expr[sourcecode.Text[T]](tree)
}
does almost what you want:
def convert[A](fn: => Text[A]): String = fn.source
convert(10 + 20 +
30
)
//10 + 20 +
// 30
Unfortunately,
if you have multiple statements in a {} block, sourcecode.Text will only capture the source code for the last expression that gets returned.
And since { object I extends Seq {} } is actually { object I extends Seq {}; () } the macro will not work in this case.
So let's write our own simple macro
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def convert(fn: => Any): String = macro convertImpl
def convertImpl(c: blackbox.Context)(fn: c.Tree): c.Tree = {
import c.universe._
val pos = fn.pos
val res = new String(pos.source.content).slice(pos.start, pos.end)
Literal(Constant(res))
}
Usage:
trait Seq
convert {
val i: Int = 1
object I extends Seq {}
10 + 20 + 30
convert(1)
}
//{
// val i: Int = 1
// object I extends Seq {}
// 10 + 20 + 30
// convert(1)
// }
Notice that arguments of def macros are typechecked before macro expansion (so convert { val i: Int = "a" }, convert { object I extends XXX } without defined XXX, convert { (; } etc. will not compile).
So I am attempting to grab the types of each field in a Scala object class:
package myapp.model
object MyObject {
val theInt: Option[Int]
}
Using the ReflectionHelper so graciously provided by Brian in this post. I use getFieldType but it returns Option[Object] instead of what it is, which is Option[Int]. The example code in that answer works for a case class, for example:
package myapp.model
case class Person(
name: String,
age: Option[Int]
)
scala> ReflectionHelper.getFieldType("myapp.model.Person", "age") // int
res12: Option[reflect.runtime.universe.Type] = Some(Option[Int])
However, if I run getFieldType on a Scala object field, we get this:
scala> ReflectionHelper.getFieldType("myapp.model.MyObject$", "theInt")
res10: Option[reflect.runtime.universe.Type] = Some(Option[Object])
What is different about Scala objects that causes this behavior and how can I get getFieldType to return Option[Int] instead of Option[Object] like it does for the case class?
Here is the ReflectionHelper from the other question for convenience:
import scala.reflect.runtime.{ universe => u }
import scala.reflect.runtime.universe._
object ReflectionHelper {
val classLoader = Thread.currentThread().getContextClassLoader
val mirror = u.runtimeMirror(classLoader)
def getFieldType(className: String, fieldName: String): Option[Type] = {
val classSymbol = mirror.staticClass(className)
for {
fieldSymbol <- classSymbol.selfType.members.collectFirst({
case s: Symbol if s.isPublic && s.name.decodedName.toString() == fieldName => s
})
} yield {
fieldSymbol.info.resultType
}
}
def maybeUnwrapFieldType[A](fieldType: Type)(implicit tag: TypeTag[A]): Option[Type] = {
if (fieldType.typeConstructor == tag.tpe.typeConstructor) {
fieldType.typeArgs.headOption
} else {
Option(fieldType)
}
}
def getFieldClass(className: String, fieldName: String): java.lang.Class[_] = {
// case normal field return its class
// case Option field return generic type of Option
val result = for {
fieldType <- getFieldType(className, fieldName)
unwrappedFieldType <- maybeUnwrapFieldType[Option[_]](fieldType)
} yield {
mirror.runtimeClass(unwrappedFieldType)
}
// Consider changing return type to: Option[Class[_]]
result.getOrElse(null)
}
}
Try
import scala.reflect.runtime.universe._
import scala.reflect.runtime
val runtimeMirror = runtime.currentMirror
runtimeMirror.staticClass("myapp.model.Person").typeSignature
.member(TermName("age")).typeSignature // => Option[Int]
runtimeMirror.staticModule("myapp.model.MyObject").typeSignature
.member(TermName("theInt")).typeSignature // => Option[Int]
In Scala if I create a class like this:
class Time(var hour: Int) {
if (hour < 0) hour = 0
}
I can comfortably create a new object using
x = new Time(4)
If I need to get the time for the x object I can do
x.hour and I get back res5: Int = 4 which is cool. But considering I want to change the hour variable of x is doing x.hour = 5 enough? I think so. Is there another way to do this.
My main question is. How would I create another object, if i didn't want to use the new keyword?
As others mentioned, you can use case classes, but case class with var constructor parameter is usually a bad choice, as it meant to be immutable. To simulate changes you can use auto-generated copy method (it became more useful, if you have multiple parameters).
scala> case class Time(hour: Int) { require(hour > 0) }
defined class Time
scala> Time(-1)
java.lang.IllegalArgumentException: requirement failed
...
scala> val t1 = Time(1)
t1: Time = Time(1)
scala> val t2 = t1.copy(hour = 2)
t2: Time = Time(2)
For more complex sample, you can check this question.
You can use a case class if you want to omit the new keyword:
case class Time(var hour: Int) {
if (hour < 0) hour = 0
}
val today = Time(-1) //> today : Time = Time(0)
Case classes can also be used in pattern matching with case statements.
today match {
case Time(0) => "foo"
case Time(1) => "bar"
} //> res0: String = foo
Here is another SO post that talks about case classes: Link
You cannot create another object without directly or indirectly using the new keyword. Case classes, seems to allow that:
case class Person(name: String)
val p1 = Person("John")
However, that case class translates into something like this:
class Person(val name: String) {
override def equals(other: AnyRef): Boolean = ???
override def hashCode: Int = ???
override def toString: String = s"Person($name)"
}
object Person {
def apply(name: String) = new Person(name)
def unapply(person: Person): Option[String] = ???
}
val p1 = Person.apply("John")
So there's an implicit new there.
First question: Yes. Run scala in a terminal and you'll get the REPL, in which you can try out stuff like this yourself.
scala> class Time(var hour: Int) {
| if (hour < 0) hour = 0
| }
defined class Time
scala> val x = new Time(4)
x: Time = Time#bcc8d5
scala> x.hour = 5
x.hour: Int = 5
scala> x.hour
res0: Int = 5
Second question: It's a little unclear what you're asking for, but I think it's this:
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Time(var hour: Int) {
if (hour < 0) hour = 0
}
object Time {
def apply(hour: Int): Time = new Time(hour)
}
// Exiting paste mode, now interpreting.
defined class Time
defined module Time
scala> val y = Time(7)
y: Time = Time#7359fe
scala> y.hour
res1: Int = 7
What is the Scala equivalent of this Java code, where someMethodThatMightThrowException is defined elsewhere?
class MyClass {
String a;
String b;
MyClass() {
try {
this.a = someMethodThatMightThrowException();
this.b = someMethodThatMightThrowException();
} finally {
System.out.println("Done");
}
}
}
class MyClass {
private val (a, b) =
try {
(someMethodThatMightThrowException(),
someMethodThatMightThrowException())
} finally {
println("Done")
}
}
try is an expression in Scala, so you can use it's value. With tuples and pattern matching you can use statement to get more than one value.
Alternatively you could use almost the same code as in Java:
class MyClass {
private var a: String = _
private var b: String = _
try {
a = someMethodThatMightThrowException()
b = someMethodThatMightThrowException()
} finally {
println("Done")
}
}
with companion object
case class MyClass(a: String, b: String)
object MyClass {
def apply() = try {
new MyClass(
a = someMethodThatMightThrowException(),
b = someMethodThatMightThrowException()
)
} finally {
println("Done")
}
}
with constructor overload a little bit harder, because we can't wrap this(...):
def tryIt[T](something: => T) = try{
something
} finally {
println("Done")
}
case class MyClass(a: String, b: String) {
def this() = this(
tryIt(someMethodThatMightThrowException),
tryIt(someMethodThatMightThrowException)
)
}
What is a or b assigned if an exception occurs? Wrap a and b in a Try to handle the exceptional cases. You can also pattern match on these to extract values.
scala> class MyClass(val a: Try[String], val b: Try[String])
defined class MyClass
scala> new MyClass(Try("foo"(0).toString), Try("foo"(3).toString))
res0: MyClass = MyClass#6bcc9c57
scala> res0.a
res1: scala.util.Try[String] = Success(f)
scala> res0.b
res2: scala.util.Try[String] = Failure(java.lang.StringIndexOutOfBoundsException: String index out of range: 3)
scala> res0.a.get
res3: String = f
scala> res0.b.get
java.lang.StringIndexOutOfBoundsException: String index out of range: 3
at java.lang.String.charAt(String.java:658)
...
Edits for comment. Uses default argumens for a and b.
null is bad but that's what you asked for. See Option
class MyClass(val a: Try[String] = null, val b: Try[String] = null)
scala> new MyClass(Success("a"))
res50: MyClass = MyClass#625aaaca
scala> res50.a
res51: scala.util.Try[String] = Success(a)
scala> res50.b
res52: scala.util.Try[String] = null
scala> new MyClass(b = Success("b"))
res53: MyClass = MyClass#68157e85
scala> res53.a
res54: scala.util.Try[String] = null
scala> res53.b
res55: scala.util.Try[String] = Success(b)
How about something closer to:
scala> def foo = ???
foo: Nothing
scala> :pa
// Entering paste mode (ctrl-D to finish)
case class Foo(a: String = Foo.afoo, b: String = Foo.bfoo)
object Foo {
import util._
def afoo = Try (foo) recover { case _ => "a" } get
def bfoo = Try (foo) recover { case _ => "b" } get
}
// Exiting paste mode, now interpreting.
warning: there were 2 feature warning(s); re-run with -feature for details
defined class Foo
defined object Foo
scala> Foo()
res0: Foo = Foo(a,b)
I add variables with Dynamic from scala 2.10.0-RC1 like this:
import language.dynamics
import scala.collection.mutable.HashMap
object Main extends Dynamic {
private val map = new HashMap[String, Any]
def selectDynamic(name: String): Any = {return map(name)}
def updateDynamic(name:String)(value: Any) = {map(name) = value}
}
val fig = new Figure(...) // has a method number
Main.figname = fig
Now, if I want to access Main.figname.number it doesn't work, because the compiler thinks it's of type Any.
But it's also Main.figname.isInstanceOf[Figure] == true, so it's Any and Figure, but doesn't have Figures abilities. Now I can cast it like, Main.figname.asInstanceOf[Figure].number and it works! This is ugly! And I can't present this to my domain users (I'd like to build a internal DSL.)
Note: If I use instead of Any the supertype of Figure it doesn't work either.
Is this a bug in scala 2.10, or a feature?
It is quite logical. You are explicitly returning instances of Any. A workaround would be to have instances of Dynamic all along:
import language.dynamics
import scala.collection.mutable.HashMap
import scala.reflect.ClassTag
trait DynamicBase extends Dynamic {
def as[T:ClassTag]: T
def selectDynamic[T](name: String): DynamicBase
def updateDynamic(name:String)(value: Any)
}
class ReflectionDynamic( val self: Any ) extends DynamicBase with Proxy {
def as[T:ClassTag]: T = { implicitly[ClassTag[T]].runtimeClass.asInstanceOf[Class[T]].cast( self ) }
// TODO: cache method lookup for faster access + handle NoSuchMethodError
def selectDynamic[T](name: String): DynamicBase = {
val ref = self.asInstanceOf[AnyRef]
val clazz = ref.getClass
clazz.getMethod(name).invoke( ref ) match {
case dyn: DynamicBase => dyn
case res => new ReflectionDynamic( res )
}
}
def updateDynamic( name: String )( value: Any ) = {
val ref = self.asInstanceOf[AnyRef]
val clazz = ref.getClass
// FIXME: check parameter type, and handle overloads
clazz.getMethods.find(_.getName == name+"_=").foreach{ meth =>
meth.invoke( ref, value.asInstanceOf[AnyRef] )
}
}
}
object Main extends DynamicBase {
def as[T:ClassTag]: T = { implicitly[ClassTag[T]].runtimeClass.asInstanceOf[Class[T]].cast( this ) }
private val map = new HashMap[String, DynamicBase]
def selectDynamic[T](name: String): DynamicBase = { map(name) }
def updateDynamic(name:String)(value: Any) = {
val dyn = value match {
case dyn: DynamicBase => dyn
case _ => new ReflectionDynamic( value )
}
map(name) = dyn
}
}
Usage:
scala> class Figure {
| val bla: String = "BLA"
| }
defined class Figure
scala> val fig = new Figure() // has a method number
fig: Figure = Figure#6d1fa2
scala> Main.figname = fig
Main.figname: DynamicBase = Figure#6d1fa2
scala> Main.figname.bla
res40: DynamicBase = BLA
All instances are wrapped in a Dynamic instance.
We can recover the actual type using the as method which performs a dynamic cast.
scala> val myString: String = Main.figname.bla.as[String]
myString: String = BLA
You can add any extensions or custom functionalities to Any or any predefined value classes. You can define an implicit value class like this:
implicit class CustomAny(val self: Any) extends AnyVal {
def as[T] = self.asInstanceOf[T]
}
Usage:
scala> class Figure {
| val xyz = "xyz"
| }
defined class Figure
scala> val fig = new Figure()
fig: Figure = Figure#73dce0e6
scala> Main.figname = fig
Main.figname: Any = Figure#73dce0e6
scala> Main.figname.as[Figure].xyz
res8: String = xyz
The implicit value class is not costly like like regular class. It will be optimised in compile time and it will be equivalent to a method call on a static object, rather than a method call on a newly instantiated object.
You can find more info on implicit value class here.