Pass class as argument to check local variable - scala

I'm currently writing a parser in Scala and am trying to create an eat function that checks whether the next Token is of a certain case class and if so, consumes it. My current try is as follows and works correctly:
def eat[T](tokenType: TypeTag[T]) = currentToken match {
case Plus() => if (tokenType == typeTag[Plus]) currentToken = lexer.getNextToken() else throw new Exception(tokenType.toString ++ " expected, " ++ currentToken.toString)
case Minus() => if (tokenType == typeTag[Minus]) currentToken = lexer.getNextToken() else throw new Exception(tokenType.toString ++ " expected, " ++ currentToken.toString)
}
Tokens are defined as follows:
trait Token
case class Plus() extends Token
case class Minus() extends Token
case class IntConst(n: Int) extends Token
case class FloatConst(x: Float) extends Token
Previously I did it with strings to specify the types, but passing a TypeTag already removes the possibility to try to eat a non existing type.
However, tldr, what I am trying to achieve is to be able to pass a type or class as argument and to check whether the currentToken is of that class.
I did find out how to pass a class as an argument with def something(c: class[_]), but then I would only know how to compare this to a given type, say Int. However, I want to compare it to the type of my currentToken. Can anybody point me in the right direction for achieving that?
Thanks.
What I am hoping to achieve, (extended version)
At the current moment, I have working code, that does what is expected in (I think) a relatively efficient way. However, for every Token case class added, a new line to this function would have to be added as well, even though the main question answered by the eat function does not change. In an ideal world, I would hope to write something like the following pseudocode:
def eat(tokenClass: Class) = {
if (classOf(currentToken) == tokenClass) getNextToken else throw exception
}
Which would never have to get extended. (Even better by the way would be if the parameter would only be allowed to be a case class of the trait Token).

Since what you want to compare is actually runtime classes (and not compile time types), you can do something like this:
def eat[T](implicit T: ClassTag[T]) =
if (T.runtimeClass == currentToken.getClass) getNextToken else throw exception
However, this will cause problems if your classes have type parameters (because of type erasure).

Related

Why does a match on covariant enum does not behave the same as with a sealed trait?

Why does this produce an error?
import scala.io.StdIn
enum Flow[+A] {
case Say (text: String) extends Flow[Unit]
case Ask extends Flow[String]
}
def eval [T](flow: Flow[T]): T = flow match {
case Flow.Say(text) => println(text)
case Flow.Ask => StdIn.readLine // error here
}
18 | case Flow.Ask => StdIn.readLine
| ^^^^^^^^^^^^^^
| Found: String
| Required: T
(no error if the enum is left invariant on T)
But when the enum is replaced with a (seemingly equivalent?) ADT implemented with a sealed trait, no such error is reported:
sealed trait Flow[+A]
object Flow {
case class Say(text: String) extends Flow[Unit]
case object Ask extends Flow[String]
}
// match statement in eval works fine
We can look at the initial proposal which added enums to Scala 3 for some insight.
By the wording of this proposal, enum cases fall into three categories.
Class cases are those cases that are parameterized, either with a type parameter section [...] or with one or more (possibly empty) parameter sections (...).
Simple cases are cases of a non-generic enum class that have neither parameters nor an extends clause or body. That is, they consist of a name only.
Value cases are all cases that do not have a parameter section but that do have a (possibly generated) extends clause and/or a body.
Let's take a look at your enum declaration.
enum Flow[+A] {
case Say (text: String) extends Flow[Unit]
case Ask extends Flow[String]
}
Now, simple cases are right out, because your enum is generic. Your Say is pretty clearly a class case, since it's parameterized. Ask, on the other hand, is non-generic and non-enumerated, so it's a value case. If we scroll down a bit, we see what value cases do
(6) A value case
case C extends <parents> <body>
expands to a value definition
val C = new <parents> { <body>; def enumTag = n; $values.register(this) }
where n is the ordinal number of the case in the companion object, starting from 0. The statement $values.register(this) registers the value as one of the enumValues of the enumeration (see below). $values is a compiler-defined private value in the companion object.
The bottom line here is that Ask is not defined as
object Ask extends Flow[String]
but more like
val Ask = new Flow[String]() { ... }
So your pattern match
case Flow.Ask => StdIn.readLine
is actually an equality check against the value Flow.Ask, rather than a type check against a singleton object. The former, unfortunately, proves nothing to the compiler about the generic type of your value, so it remains T, as opposed to specializing to String.
The rationale for this is provided on the same page
Objectives
...
Enumerations should be efficient, even if they define many values. In particular, we should avoid defining a new class for every value.
...
So it seems the Scala developers wanted to avoid the bloat that would result from an enum declaring tons of unparameterized values (i.e. a type that looks like an ordinary Java-style enum).
The simple solution, then, is to provide a parameter list
case Ask() extends Flow[String]
It's ever so slightly more cumbersome to work with, but it does define a new type, and then your pattern match
case Flow.Ask() => StdIn.readLine
will succeed

Scalatest custom matchers for 'should contain'

This is a situation I have encountered frequently, but I have not been able to find a solution yet.
Suppose you have a list of persons and you just want to verify the person names.
This works:
persons.map(_.name) should contain theSameElementsAs(List("A","B"))
Instead, I would rather write this like
val toName: Person => String = _.name
persons should contain theSameElementsAs(List("A","B")) (after mapping toName)
because this is how you would say this.
Sometimes however, you'd like to use a custom matcher which matches more than just one property of the object. How would it be possible to use
persons should contain(..)
syntax, but somehow be able to use a custom matcher?
Both these situations I could easily solve using JUnit or TestNG using Hamcrest matchers, but I have not found a way to do this with ScalaTest.
I have tried to use the 'after being' syntax from the Explicitly trait, but that's not possible since this takes a 'Normalization' which defines that the 'normalized' method uses the same type for the argument and return type. So it's not possible to change a Person to a String.
Also I have not succeeded yet in implementing an 'Explicitly' like trait because it does not like the Equality[.] type I return and/or it does not know anymore what the original list type was, so using '_.name' does not compile.
Any suggestions are welcome.
You can manage something similar via the word decided and moderate abuse of the Equality trait. This is because the Equality trait's areEqual method takes a parameter of the generic type and one of type Any, so you can use that to compare Person with String, and decided by simply takes an Equality object which means you don't have to futz around with Normality.
import org.scalactic.Equality
import org.scalatest.{FreeSpec, Matchers}
final class Test extends FreeSpec with Matchers {
case class Person(name: String)
val people = List(Person("Alice"), Person("Eve"))
val namesBeingEqual = MappingEquality[Person, String](p => p.name)
"test should pass" in {
(people should contain theSameElementsAs List("Alice", "Eve"))(
decided by namesBeingEqual)
}
"test should fail" in {
(people should contain theSameElementsAs List("Alice", "Bob"))(
decided by namesBeingEqual)
}
case class MappingEquality[S, T](map: S => T) extends Equality[S] {
override def areEqual(s: S, b: Any): Boolean = b match {
case t: T => map(s) == t
case _ => false
}
}
}
I'm not sure I'd say this is a good idea since it doesn't exactly behave in the way one would expect anything called Equality to behave, but it works.
You can even get the beingMapped syntax you suggest by adding it to after via implicit conversion:
implicit class AfterExtensions(aft: TheAfterWord) {
def beingMapped[S, T](map: S => T): Equality[S] = MappingEquality(map)
}
}
I did try getting it work with after via the Uniformity trait, which has similar methods involving Any, but ran into problems because the normalization is the wrong way around: I can create a Uniformity[String] object from your example, but not a Uniformity[Person] one. (The reason is that there's a normalized method returning the generic type which is used to construct the Equality object, meaning that in order to compare strings with strings the left-side input must be a string.) This means that the only way to write it is with the expected vs actual values in the opposite order from normally:
"test should succeed" in {
val mappedToName = MappingUniformity[Person, String](person => person.name)
(List("Alice", "Eve") should contain theSameElementsAs people)(
after being mappedToName)
}
case class MappingUniformity[S, T](map: S => T) extends Uniformity[T] {
override def normalizedOrSame(b: Any): Any = b match {
case s: S => map(s)
case t: T => t
}
override def normalizedCanHandle(b: Any): Boolean =
b.isInstanceOf[S] || b.isInstanceOf[T]
override def normalized(s: T): T = s
}
Definitely not how you'd usually want to write this.
use inspectors
forAll (xs) { x => x should be < 3 }

avoid type conversion in Scala

I have this weird requirement where data comes in as name ->value pair from a service and all the name-> value type is string only (which really they are not but that's how data is stored)
This is a simplified illustration.
case class EntityObject(type:String,value:String)
EntityObject("boolean","true")
now when getting that EntityObject if type is "boolean" then I have to make sure value is not anything else but boolean so first get type out and check value and cast value to that type. e.g in this case check value is boolean so have to cast string value to boolean to validate. If it was anything else besides boolean then it should fail.
e.g. if data came in as below, casting will fail and it should report back to the caller about this error.
EntityObject("boolean","1")
Due to this weird requirement it forces type conversion in validation code which doesn't look elegant and against type safe programming. Any elegant way to handle this in scala (may be in a more type safe manner)?
Here is where I'm going to channel an idea taken from a tweet by Miles Sabin in regards to hereogenous mappings (see this gist on github.) If you know the type of object mapping names a head of time you can use a nifty little trick which involves dependent types. Hold on, 'cause it's a wild ride:
trait AssocConv[K] { type V ; def convert: String => V }
def makeConv[V0](name: String, con: String => V0) = new AssocConv[name.type]{
V = V0
val convert = con
}
implicit val boolConv = makeConv("boolean", yourMappingFunc)
def convEntity(name: String, value: String)(implicit conv: AssocConv[name.type]): Try[conv.V] = Try{ conv.convert(value) }
I haven't tested this but it "should" work. I've also enclosed it in a Scala Try so that it catches exceptions thrown by your conversion function (in case you're doing things like _.toInt as the converter.)
You're really talking about conversion, not casting. Casting would be if the value really were an instance of Boolean at runtime, whereas what you have is a String representation of a Boolean.
If you're already working with a case class, I think a pattern matching expression would work pretty well here.
For example,
def convert(entity : EntityObject) : Any = entity match {
case EntityObject("boolean", "true") => true
case EntityObject("boolean", "false") => false
case EntityObject("string", s) => s
// TODO: add Regex-based matchers for numeric types
}
Anything that doesn't match one of the specified patterns would cause a MatchError, or you could put a catchall expression at the end to throw your own exception.
In this particular example, since the function returns Any, the calling coffee would need to do an actual type cast to get the specific type, but at least by that point all validation/conversion would have already been performed. Alternatively, you could just put the code that uses the values directly into the above function and avoid casting. I don't know what your specific needs are, so I can't offer anything more detailed.

Making code more scala idiomatic

I came across following java like code in Scala project. how to make it more Scala idiomatic with no side effects (exception handling appropriately) ?
I am thinking to use scalaz disjunction / (I know I can use Scala either too but like right biased more I guess). in a function there are a few such if checks(one above is one example) which throw one or the other type of exceptions. how to make such code more Scala idiomatic?
EDIT:
Question is not around how to convert Java null checks into Scala Idiomatic, which I am already doing. for e.g. following
hpi.fold(throw new Exception("Instance not found for id " + processInstanceId)) { h =>
val pi = new ProcessInstance(taskResponse)
Now return type of the existing function is some value say "ProcessInstance" for e.g. but in my opinion is misleading. caller would never know if this will throw an exception so my question is more around returning Either[Error,Value] from such functions. And if I have a few such exceptions being captured into a single function, how to accumulate them all and reflect into return type?
One thought might making processDefinition.getDiagramResourceName() return an Option, so you can then check whether the result is Some(x) or None.
Using scalaz and being idiomatic this is probably what I would end up with (subject to refactoring):
for {
pd <- Option(processDefinition.getDiagramResourceName()).\/>("Diagram resource could not be found")
} yield pd
So if you have null you get back Left("Diagram resource could not be found") otherwise you get Right(DiagramResourceName).
An approach based in case classes where different subclasses of names, references or labels may be defined,
trait ResourceName
case object MissingName extends ResourceName
case class DiagramResourceName(name: String) extends ResourceName
case class AnotherResourceName(ref: Int) extends ResourceName
processDefinition.getDiagramResourceName() match {
case DiagramResourceName(name) => println(s"name $name")
case MissingName => throw new ActivityException(errorMessage)
}

Scala: Compare types

I want to define a function that could compare two class types. I have defined two different classes:
abstract class Task
case class DefinedTask(id: Long) extends Task
case class EmptyTask() extends Task
Then I have a function that returns an object of type Task, that could be either DefinedTask or EmptyTask.
Now, what I'd like to do is to have a function that identifies if this object is a DefinedTask or just an EmptyTask. The problem would be simple, I'd use pattern matching. But I want to generalize it because multiple classes go with this Defined/Empty pattern.
What I'd tried so far is:
def makeReturned[T: Manifest, U: Manifest](obj: T)(u: U)(f: T => Value) =
if(manifest[U] equals manifest[T]) f(obj) else
throw new IllegalArgumentException()
}
//call to it
makeReturned(task)(DefinedTask)(makeTask)
U is always DefinedTask, T could be either DefinedTask or EmptyTask, but it is returned as Task.
manifest[U].erasure.toString //"class DefinedTask$"
manifest[T].erasure.toString //"class Task"
Which is right from the compiler's stand point but it's not for me. So, my question is how could I compare them in a way that would give me what I want?
It looks like you want run-time, not compile-time checking. So I think you mean
def makeReturned[U <: Task, T <: Task](obj: T)(u: U)(f: T => Value) = {
if (obj.getClass.isInstance(u.getClass)) f(obj)
else throw new IllegalArgumentException
}
or something like that. Look at the methods on java.lang.Class and pick the one that does what you want.
There are some mistakes in your code:
You should make the abstract class Task sealed for exhaustive pattern matching
Empty case classes are deprecated. The compiler should have warned you about it. case object EmptyTask extends Task would be the correct alternative
Both case classes and case objects extend the trait Product. You can check the product on being empty with either of the following ways:
task.productArity == 0
task.productIterator.isEmpty
I think you'd be much better off reapproaching your problem. Why not just use the standard Option and have the instances of a simple case class Task(id: Int) wrapped in it? This could be the general approach for all the other similar entities of yours.