Appending a label to immutable case classes in Scala - scala

Im trying to create a parser for a small language with commands including labels and goto:
...
lazy val cmds = opt("{")~>rep(cmd<~opt(";"))<~opt("}") ^^ {...}
lazy val cmd = ("if"~boolexpr~"then"~cmds~"else"~cmds
^^ { case _~b~_~c1~_~c2 => IFCMD(boolexpr,c1
| ident ~":="~numericLit ^^ {case i1~_~v => ASSIGN(i1,v) }
| "goto" ~>ident ^^ { case l => GOTO(l) }
| ident~":"~cmd ^^ { case l~_~c => <APPENDLABELTO_CORE>
...
the GOTO, IFCMD etc are case classes extending abstract class Core
In keeping with the functional/scala-like/immutable-objecty -way I'm thinking that defining Core like this is wrong:
abstract class Core(var label:Option[String] = None )
but would allow me to replace the part with <APPENDLABELTO_CORE> with:
| ident~":"~cmd ^^ { case l~_~c => c.label = Some(l); c }
Can anyone point out the "scalaish" way to do this?
( I've tried c copy (label=Some(l)) but the abstract base class hasn't got the automatic copy constructor magic )

It is entirely possible to create your own copy-like method:
abstract class Core(val label: Option[String]) {
def set(label: Option[String]): Core
}
class Impl(label: Option[String] = None) extends Core(label) {
def set(label: Option[String] = this.label) = new Impl(label)
}
used thusly:
scala> val i = new Impl
i: Impl = Impl#1930ebb
scala> i.label
res0: Option[String] = None
scala> i.set(label = Some("thing"))
res1: Impl = Impl#b28f30
scala> res1.label
res2: Option[String] = Some(thing)
But, pragmatically, I wouldn't be too quick to dismiss the use of vars here. It is easier to reason about immutable values, but the ones you get are pretty well isolated within the parser, as far as I can tell. An alternative idea would be to create a method that converts everything to an immutable version at the end, or if the parser code ends up storing all the data elsewhere anyway, just leaving it mutable.
Another way to go is to make the abstract class not abstract, but to actually make it a case class. You can derive classes from a case class (deriving case classes from case classes is a no-no, however). The trick then would be to make your variable data that you may need to preserve live in a field:
abstract class SpecializedStuff { }
case class ParticularStuff(val i: Int) extends SpecializedStuff
case class Core(details: SpecializedStuff, label: Option[String] = None)
class Impl(p: ParticularStuff) extends Core(p)
scala> val i = new Impl( ParticularStuff(5) )
i: Impl = Core(ParticularStuff(5),None)
scala> i.copy(label = Some("thing"))
res0: Core = Core(ParticularStuff(5),Some(thing))

Related

Scala ClassCastException on Option.orNull

When I try to run following code:
def config[T](key: String): Option[T] = {
//in reality this is a map of various instance types as values
Some("string".asInstanceOf[T])
}
config("path").orNull
I'm getting error:
java.lang.String cannot be cast to scala.runtime.Null$
java.lang.ClassCastException
Following attempts are working fine:
config[String]("path").orNull
config("path").getOrElse("")
Since getOrElse works its confusing why null is so special and throws an error. Is there a way for orNull to work without specifying generic type ?
scalaVersion := "2.12.8"
Just to show how you may avoid the use asInstanceOf to get the values from a typed config.
sealed trait Value extends Product with Serializable
final case class IntValue(value: Int) extends Value
final case class StringValue(value: String) extends Value
final case class BooleanValue(value: Boolean) extends Value
type Config = Map[String, Value]
sealed trait ValueExtractor[T] {
def extract(config: Config)(fieldName: String): Option[T]
}
object ValueExtractor {
implicit final val IntExtractor: ValueExtractor[Int] =
new ValueExtractor[Int] {
override def extract(config: Config)(fieldName: String): Option[Int] =
config.get(fieldName).collect {
case IntValue(value) => value
}
}
implicit final val StringExtractor: ValueExtractor[String] =
new ValueExtractor[String] {
override def extract(config: Config)(fieldName: String): Option[String] =
config.get(fieldName).collect {
case StringValue(value) => value
}
}
implicit final val BooleanExtractor: ValueExtractor[Boolean] =
new ValueExtractor[Boolean] {
override def extract(config: Config)(fieldName: String): Option[Boolean] =
config.get(fieldName).collect {
case BooleanValue(value) => value
}
}
}
implicit class ConfigOps(val config: Config) extends AnyVal {
def getAs[T](fieldName: String)(default: => T)
(implicit extractor: ValueExtractor[T]): T =
extractor.extract(config)(fieldName).getOrElse(default)
}
Then, you can use it like this.
val config = Map("a" -> IntValue(10), "b" -> StringValue("Hey"), "d" -> BooleanValue(true))
config.getAs[Int](fieldName = "a")(default = 0) // res: Int = 10
config.getAs[Int](fieldName = "b")(default = 0) // res: Int = 0
config.getAs[Boolean](fieldName = "c")(default = false) // res: Boolean = false
Now, the problem becomes how to create the typed config from a raw source.
And even better, how to directly map the config to a case class.
But, those are more complex, and probably is better to just use something already done, like pureconfig.
Just as an academic exercise, lets see if we can support Lists & Maps.
Lets start with lists, a naive approach would be to have another case class for values which are lists, and create a factory of extractors for every kind of list (this process is formally know as implicit derivation).
import scala.reflect.ClassTag
final case class ListValue[T](value: List[T]) extends Value
...
// Note that, it has to be a def, since it is not only one implicit.
// But, rather a factory of implicits.
// Also note that, it needs another implicit parameter to construct the specific implicit.
// In this case, it needs a ClasTag for the inner type of the list to extract.
implicit final def listExtractor[T: ClassTag]: ValueExtractor[List[T]] =
new ValueExtractor[List[T]] {
override def extract(config: Config)(fieldName: String): Option[List[T]] =
config.get(fieldName).collect {
case ListValue(value) => value.collect {
// This works as a safe caster, which will remove all value that couldn't been casted.
case t: T => t
}
}
}
Now, you can use it like this.
val config = Map("l" ->ListValue(List(1, 2, 3)))
config.getAs[List[Int]](fieldName = "l")(default = List.empty)
// res: List[Int] = List(1, 2, 3)
config.getAs[List[String]](fieldName = "l")(default = List("Hey"))
// res: String = List() - The default is not used, since the field is a List...
// whose no element could be casted to String.
However, this approach is limited to plain types, if you need a List of other generic type, like a List of Lists. Then, this won't work.
val config = Map("l" ->ListValue(List(List(1, 2), List(3))))
val l = config.getAs[List[List[String]]](fieldName = "l")(default = List.empty)
// l: List[List[String]] = List(List(1, 2), List(3)) ???!!!
l.head
// res: List[String] = List(1, 2)
l.head.head
// java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
The problem here is type erasure, which ClassTags can not solve, you may try to use TypeTags which can preserve the complete type, but the solution becomes more cumbersome.
For Maps the solution is quite similar, especially if you fix the key type to String (assuming what you really want is a nested config). But, this post is too long now, so I would leave it as an exercise for the reader.
Nevertheless, as already said, this can be broken easily, and is not completely robust.
There are better approaches, but I myself am not very skilled on those (yet), and even if I would be, the answer would be more long and really not necessary at all.
Lucky for you, even if pureconfig does not support YAML directly, there is a module which does, pureconfig-yaml.
I would suggest you to take a look to the module, and if you have further problems ask a new question tagging pureconfig and yaml directly. Also, if it is just a small doubt, you may try asking in thegitter channel.

Scala Reflection to get the types of all fields of an object

I need to create a function which is accepting two objects of same class. One is the updated object and other one is the old object. I need to find the differences in updated object by considering the old object. Like we have getDeclaredFields method in java to fetch all the variables.I am seeking for a way to get all the fields of an object and then i have to iterate one by one field and on the basis of its type i have to check equals on both the objects.
// code from comment included:
def trackChanges(newRecord:Object,oldRecord:Object) :String = {
val fields :Array[Field] = newRecord.getClass.getDeclaredFields
var check : String = "Equal"
for( i <- 0 to fields.length-1) {
fields(i).setAccessible(true)
val fieldType:Object = fields(i).getType
fieldType match {
case x: String => fields(i).get(newRecord).equals(fields(i).get(oldRecord))
case x: java.lang.Double => println("String")
case x: Seq[] => println("String")
case x: List[] => }
So you've got some objects:
scala> trait MyTrait {
| val x: String
| val y: Int
| }
defined trait MyTrait
scala> object MyObjectA extends MyTrait {
| val x = "priyam"
| val y = 1
| }
defined object MyObjectA
scala> object MyObjectB extends MyTrait {
| val x = "singh"
| val y = 2
| }
defined object MyObjectB
scala> object MyObjectC extends MyTrait {
| val x = "priyam"
| val y = 1
| }
defined object MyObjectC
Since you can't compare two objects, you could create a case class from your object. That would give you a comparator for free:
scala> def createFromObject(obj: MyTrait): MyCaseClass = MyCaseClass(obj.x, obj.y)
createFromObject: (obj: MyTrait)MyCaseClass
And now, you compare the objects:
scala> createFromObject(MyObjectA) == createFromObject(MyObjectC)
res5: Boolean = true
scala> createFromObject(MyObjectA) == createFromObject(MyObjectB)
res6: Boolean = false
You can also call individual members from the original object or the case class:
scala> MyObjectA.x
res7: String = priyam
scala> createFromObject(MyObjectA).a
res8: String = priyam
Idea 1.
Do not use reflection at runtime. Reflection is heavy and slow mechanism, so using it for tracking changes in objects may kill all performance of your solution. I recommend you to write it directly, for each field, by hand. It would be fast.
if (obj1.field != obj2.field) {}
Idea 2.
But I assume that you mean yourself as good programmer, and you worry about future code maintainance, and I assume you are to lazy to write it by hand. So. Because scala runs on JVM, java-reflection is also awailable here. you may use getDeclaredFields freely.
If you want to use scala reflection, you may see here : https://github.com/yudnikov/transactions/blob/master/src/main/scala/ru/yudnikov/meta/describing/Reflector.scala
- here are examples of scala reflection usage. Pay attention to
def getTerms(...)
and you'll need to understand what is runtime mirror...
Idea 3.
The true programmers solution for this problem is to use scala macros with reflection at compile time to generate low-level lightweight code from Idea №1 automatically, during compilation. But I can't help you with this. Good luck ;)
def trackChanges(newRecord:Object,oldRecord:Object) :String = {
val fields :Array[Field] = newRecord.getClass.getDeclaredFields
var check : String = "Equal"
for( i <- 0 to fields.length-1)
{
fields(i).setAccessible(true)
val fieldType:Object= fields(i).getType
fieldType match
{
case x: String=> fields(i).get(newRecord).equals(fields(i).get(oldRecord))
case x: java.lang.Double => println("String")
case x: Seq[_] => println("String")
case x: List[_] =>
}

A more functional way to write this?

I was thinking about something, I wrote this trait with two classes extending it and another class that may contain them:
sealed trait MainObj
case object subObj1 extends mainObj
case Object subObj2 extends mainObj
case class AnotherClass(val mo: Option[MainObj], val amount: Int)
Now let's say I wanted to write a function that added the amounts in twoAnotherClass objects but only if the optional MainObj inside each of them were the same type. Like only add if both are subObj1.
So I could do something like this:
def add(one: AnotherClass, two: AnotherClass): AnotherClass = one. mo, two.mo match {
case (Some(x), Some(y)) if i and x are the same class => return a `AnotherClass` with the two integers added from `one` and `two`
etc..
I wondered whether there was another way of doing this? I don't know whether this is a "functional" way of doing it or whether there is a less verbose way?
I ask because essentially I could write some more methods like subtract, multiply, etc ... and I have some very common code.
I could extract that common code and write a function that simply takes two of the subObjs and an operation and then apply that operation on the two objects, but that only abstracts out the common operation, could the main pattern matching part be written differently that may be considered more concise(for lack of a better word)?
Just add the 'add' method to the case class :
sealed trait MainObj
case object SubObj1 extends MainObj
case object SubObj2 extends MainObj
case class AnotherClass(val mo: Option[MainObj], val amount: Int){
def add(that:AnotherClass):AnotherClass = {
if (that.mo == this.mo)
this.copy(amount = this.amount + 1)
else
this
}
}
val x = AnotherClass(Some(SubObj1), 1)
val y = AnotherClass(Some(SubObj1), 1)
val z = AnotherClass(Some(SubObj2), 1)
scala> x add y
res5: AnotherClass = AnotherClass(Some(SubObj1),2)
scala> x add z
res6: AnotherClass = AnotherClass(Some(SubObj1),1)
scala> val l = List(x,y,z)
l.reduce ( _ add _)
res7: AnotherClass = AnotherClass(Some(SubObj1),2)
val mo = two.mo
one match {
case AnoterClass(`mo`, am) =>
one.copy(amount = am + two.amount)
case _ => ???
}

Use Scala macros to generate methods

I want to generate aliases of methods using annotation macros in Scala 2.11+. I am not even sure that is even possible. If yes, how?
Example - Given this below, I want the annotation macros to expand into
class Socket {
#alias(aliases = Seq("!", "ask", "read"))
def load(n: Int): Seq[Byte] = {/* impl */}
}
I want the above to generate the synonym method stubs as follows:
class Socket {
def load(n: Int): Seq[Byte] = // ....
def !(n: Int) = load(n)
def ask(n: Int) = load(n)
def read(n: Int) = load(n)
}
The above is of course a facetious example but I can see this technique being useful to auto generate sync/async versions of APIs or in DSLs with lots of synonyms. Is it possible to also expose these generated methods in the Scaladoc too? Is this something possible using Scala meta?
Note: What I am asking is quite different from: https://github.com/ktoso/scala-macro-method-alias
Also please don't mark this as a duplicate of this as the question is a bit different and a lot has changed in Scala macro land in past 3 years.
This doesn't seem possible exactly as stated. Using a macro annotation on a class member does not allow you to manipulate the tree of the class itself. That is, when you annotate a method within a class with a macro annotation, macroTransform(annottees: Any*) will be called, but the only annottee will be the method itself.
I was able to get a proof-of-concept working with two annotations. It's obviously not as nice as simply annotating the class, but I can't think of another way around it.
You'll need:
import scala.annotation.{ StaticAnnotation, compileTimeOnly }
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
The idea is, you can annotate each method with this annotation, so that a macro annotation on the parent class is able to find which methods you want to expand.
class alias(aliases: String *) extends StaticAnnotation
Then the macro:
// Annotate the containing class to expand aliased methods within
#compileTimeOnly("You must enable the macro paradise plugin.")
class aliased extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro AliasMacroImpl.impl
}
object AliasMacroImpl {
def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
val result = annottees map (_.tree) match {
// Match a class, and expand.
case (classDef # q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }") :: _ =>
val aliasedDefs = for {
q"#alias(..$aliases) def $tname[..$tparams](...$paramss): $tpt = $expr" <- stats
Literal(Constant(alias)) <- aliases
ident = TermName(alias.toString)
} yield {
val args = paramss map { paramList =>
paramList.map { case q"$_ val $param: $_ = $_" => q"$param" }
}
q"def $ident[..$tparams](...$paramss): $tpt = $tname(...$args)"
}
if(aliasedDefs.nonEmpty) {
q"""
$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self =>
..$stats
..$aliasedDefs
}
"""
} else classDef
// Not a class.
case _ => c.abort(c.enclosingPosition, "Invalid annotation target: not a class")
}
c.Expr[Any](result)
}
}
Keep in mind this implementation will be brittle. It only inspects the annottees to check that the first is a ClassDef. Then, it looks for members of the class that are methods annotated with #alias, and creates multiple aliased trees to splice back into the class. If there are no annotated methods, it simply returns the original class tree. As is, this will not detect duplicate method names, and strips away modifiers (the compiler would not let me match annotations and modifiers at the same time).
This can easily be expanded to handle companion objects as well, but I left them out to keep the code smaller. See the quasiquotes syntax summary for the matchers I used. Handling companion objects would require modifying the result match to handle case classDef :: objDef :: Nil, and case objDef :: Nil.
In use:
#aliased
class Socket {
#alias("ask", "read")
def load(n: Int): Seq[Byte] = Seq(1, 2, 3).map(_.toByte)
}
scala> val socket = new Socket
socket: Socket = Socket#7407d2b8
scala> socket.load(5)
res0: Seq[Byte] = List(1, 2, 3)
scala> socket.ask(5)
res1: Seq[Byte] = List(1, 2, 3)
scala> socket.read(5)
res2: Seq[Byte] = List(1, 2, 3)
It can also handle multiple parameter lists:
#aliased
class Foo {
#alias("bar", "baz")
def test(a: Int, b: Int)(c: String) = a + b + c
}
scala> val foo = new Foo
foo: Foo = Foo#3857a375
scala> foo.baz(1, 2)("4")
res0: String = 34

Using a scala extractor as a parser

I keep coming across situations where I want to use extractors as parsers, they are really useful for this but it never looks right, often the unapply looks like it should be an apply. Also, the parsing extractor may get in the way of the default extractor. Are there any patterns for this?
case class AnID(int: Int) extends AnyVal
object AnID {
def unapply(idString: String): Option[AnID] = "id-([0-9]+)".r match {
case Seq(intString: String) => Try(Integer.parseInt(intString)).map(AnID.apply).toOption
case _ => None
}
}
And a test:
AnID(8) should be (AnID(8))
val AnID(id1) = "id-1"
id1 should be (AnID(1))
val AnID(id2) = AnID(2)
id2 should be (2)
It is kind of strange.
You can create a Parse object inside the companion object to make it more clear that you're parsing.
case class AnID(int: Int) extends AnyVal
object AnID {
private val Reg = "id-([0-9]+)".r
object Parse {
def unapply(s: String): Option[AnID] = s match {
case Reg(digits) => Some(new AnID(digits.toInt))
case _ => None
}
}
}
So now you at least don't clobber your normal extractor and have things that look like val AnID.Parse(id) = "id-9".
Maybe that won't solve your general unease with pattern matching looking kind of backwards. If not, you can always make Parse just implement an apply, and then you get val Option(x) = AnID.Parse("id-9").