working with class as function parameter in Scala - scala

Let's say I have the following function:
def sampleFunc (c : Class[]) : Boolean
It takes a class as parameter. It then checks if a certain element el is of type Class[].
I tried accomplishing that by doing
el.isInstanceOf[Class[]]
But that doesn't work, it always returns false.
Does someone see what I'm doing wrong here?

c.isInstance(el)
is the dynamic equivalent of the instanceof operator in Java (i.e. the isInstanceOf method in Scala).

You need to use a type class scala.reflect.ClassTag[T]
import scala.reflect.ClassTag
import scala.reflect.classTag
def sampleFunc[T: ClassTag](el: Any): Boolean = {
classTag[T].runtimeClass.isInstance(el)
}
or via pattern matching
def sampleFunc[T: ClassTag](el: Any): Boolean = {
el match {
case _: T => true
case _ => false
}
}
However, el.isInstance[T] is still not supported because of type erasure in java.
Now
println(sampleFunc[String](""))
println(sampleFunc[String](1))
will print true and false respectively.

Related

Returning functions that check for equality/ordinal comparison for any valid type parameter

I'm not very experienced with using Scala and I think I'm missing something when it comes to implicits. I'm essentially trying to take an enumerated argument that represents a certain logical operator (e.g. representing greater than '>' as the enumerated value Greater) and return a function that will apply that operator to a left and right operand and return the boolean result.
So, for example, if I had something like the following:
val gt = LogicalOperator[Int](Greater)
then gt(2, 1) would return True. I'd also like this to work for the == and != operators as well but additionally extended to iterables (e.g. eq(List(1,2,3), List(1,2,3)) returns True).
So basically I want to be able to generate comparative functions for a generic type parameter of Ordering or Iterable and be able to pass the function around to other methods and/or objects. I've been trying to use Typeclasses with implicits but I'm running into issues with using traits such as Ordering as type parameters.
Here is basically what I have so far. Started with the enumerated operators:
object LogicalOperation extends Enumeration {
type LogicalOperation = Value
val Greater, GreaterEqual, Less, LessEqual, Equal, NotEqual = Value
def fromName(s: String): Value = values.find(_.toString == s).get
}
Then trying to create some implicit operator factories:
sealed trait OperatorFactory[T] {
def apply(operation: LogicalOperation): (T, T) => Boolean
}
object OperatorFactory {
implicit class OrderedOperator[T: Ordering](operation: LogicalOperation)(implicit ord: Ordering[T]) extends OperatorFactory[T] {
def apply(operation: LogicalOperation): (T, T) => Boolean = {
operation match {
case Greater => ord.gt
case GreaterEqual => ord.gteq
case Less => ord.lt
case LessEqual => ord.lteq
case Equal => ord.equiv
case NotEqual => (l: T, r: T) => !ord.equiv(l, r)
}
}
}
implicit class IterableOperator[Iterable](operation: LogicalOperation) extends OperatorFactory[Iterable] {
def apply(operation: LogicalOperation): (Iterable, Iterable) => Boolean = {
operation match {
case Equal => (l: Iterable, r: Iterable) => l.equals(r)
case NotEqual => (l: Iterable, r: Iterable) => !l.equals(r)
case _ => throw new IllegalArgumentException(s"Logical operation ${operation} not applicable for Iterables.")
}
}
}
}
Then creating an operator object to implicitly select the right factory and return the operator function (I think this is part of what is not correct):
object LogicalOperator {
implicit def OrderedOperator[T: Ordering](operation: LogicalOperation) = OperatorFactory.OrderedOperator[T](operation)
implicit def IterOperator[Iterable](operation: LogicalOperation) = OperatorFactory.IterableOperator[Iterable](operation)
def apply[T](operation: LogicalOperation)(implicit operatorFactory: OperatorFactory[T]): (T, T) => Boolean = {
operatorFactory.apply(operation)
}
}
Now, I'm running into a couple of compile errors. If I try to instantiate one of these operator functions as follows:
val gt = LogicalOperator[Int](Greater)
I get basically the following error:
could not find implicit value for parameter operatorFactory: OperatorFactory[Int]
Edit: Tim's answer helped correct this issues:
If I remove that line of code, then I get errors on the implicit classes of the OperatorFactory:
class OrderedOperator needs to be abstract, since method apply in trait OperatorFactory of type [T](operation: LogicalOperation.LogicalOperation)(T, T) => Boolean is not defined
So I think there are issues both with how I'm trying to implicitly instantiate the OperatorFactory and with how the abstract methods for the operator factory are implemented.
I'm also wondering if there is just a simpler way to instantiate and pass around these comparative functions.
sealed trait OperatorFactory[T] {
def apply[T](operation: LogicalOperation): (T, T) => Boolean
}
This code has two type parameters called T. The first is the type parameter of the trait, and the second is the type parameter of apply. You probably want to use the same type in both places, so remove the type parameter from apply:
sealed trait OperatorFactory[T] {
def apply(operation: LogicalOperation): (T, T) => Boolean
}
Enabling the compiler option -Xlint:type-parameter-shadow should generate a warning for this.

Scala - missing parameter type - is it possible to avoid assisting the compiler?

This works, but I would like to avoid assisting the compiler as I have no idea what the tag type should be, I just know it will be of type Field.
val x: TypeString = TypeString("test")
TypeValidator.validate[TypeString](x, x => {
true
})
What I would ideally like to have is: (where x type is inferred)
TypeValidator.validate(x, x => {
true
})
The validation class is as follows
import models.implementations.Field
object TypeValidator {
def apply(): TypeValidator = {
new TypeValidator()
}
def validate[T <: Field](t: T, v: T => Boolean): Boolean = {
new TypeValidator().validate(t, v)
}
}
class TypeValidator {
def validate[T <: Field](t: T, v: T => Boolean): Boolean = v.apply(t)
}
Having searched around on here for about an hour, I've come to the conclusion I might not be able to avoid this, but I would still like to hope someone has a solution.
Perhaps the closest I've come to finding an answer was here:
scala anonymous function missing parameter type error
Update - just to add, this does work, but I feel there might be a better solution still:
TypeValidator.validate(x)(x => {
true
})
Changed the class to ad a second set of parameters for the anonymous function.
class TypeValidator {
def validate[T <: Field](t: T)(v: T => Boolean): Boolean = v.apply(t)
}
There is no better solution than
class TypeValidator {
def validate[T <: Field](t: T)(v: T => Boolean): Boolean = v.apply(t)
}
Any other solution will needlessly complicate the signature of validate.
Scala's type inferencer goes through parameter lists one by one, so when it saw the old version, it tried to infer T from both the function argument and the Field argument, and failed because the type of the function argument was no fully known. Here, the inferencer takes the Field argument without thinking about the function argument, and infers that T = TypeString. This allows it to then infer the function argument's argument's type.
You will find that this is a very common pattern throughout the Scala standard library and basically all other Scala libraries.
Further, you can and should omit the parentheses around the function argument:
TypeValidator.validate(x) { x =>
true
}

Why does this code with free monad interpreter compile?

I'm trying to understand free monads. So with help of tutorials I wrote toy example to play with and now I don't understand why does it compile. Here it is:
import cats.free.Free
import cats.instances.all._
import cats.~>
trait Operation[+A]
case class Print(s: String) extends Operation[Unit]
case class Read() extends Operation[String]
object Console {
def print(s: String): Free[Operation, Unit] = Free.liftF(Print(s))
def read: Free[Operation, String] = Free.liftF(Read())
}
object Interpreter extends (Operation ~> Option) {
// why does this compile?
override def apply[A](fa: Operation[A]): Option[A] = fa match {
case Print(s) => Some(println(s))
case Read() => Some(readLine())
}
}
object Main {
def main(args: Array[String]) {
val program = for {
_ <- Console.print("What is your name?")
name <- Console.read
_ <- Console.print(s"Nice to meet you $name")
} yield ()
program.foldMap(Interpreter)
}
}
I'm talking about apply method of Interpreter. It should return Option[A], but I can return Option[Unit] and Option[String] here so I assume it should be a compilation error. But it's not. This code compiles and works(although Idea tells me that it's an error). Why is that?
UPD: but why doesn't this compile?
def test[A](o: Operation[A]): Option[A] = o match {
case Print(s) => Some(s)
case Read() => Some(Unit)
}
Your apply method is supposed to return Option[A] where A is determined by the type of the argument. That is if the argument has type Operation[Unit], the result should also be an Option[Unit] and so on.
Now your body adheres to that contract perfectly. Yes, you do have a case where you return an Option[Unit] instead of a general Option[A], but you only do that if the argument was an instance of Print and thus an Operation[Unit]. That is you only ever return an Option[Unit] when the argument was an Operation[Unit], so the contract is not broken. The same is true with Read and String. Note that if you returned an Option[Unit] in the case for Read, that'd be an error because you'd now be returning a type other than that of the argument.
So that's why the code is semantically correct, but why does it compile? That's because the Scala type checker (unlike IntelliJ's approximation thereof) is smart enough to take the additional type information into account when pattern matching. That is, in the case Print it knows that you've just matched a value of type Operation[A] against a pattern of type Operation[Unit], so it assigns A = Unit inside the case's body.
Regarding your update:
case Print(s) => Some(s)
Here we have a pattern of type Operation[Unit] (remember that Print extends Operation[Unit]), so we should get a result of type Option[Unit], but Some(s) has type Option[String]. So that's a type mismatch.
case Read() => Some(Unit)
First of all Unit it the companion object of the Unit type, so it has its own type, not type Unit. The only value of type Unit is ().
Aside from that, it's the same situation as above: The pattern has type Operation[String], so the result should be Operation[String], not Operation[Unit] (or Operation[Unit.type]).

Can we elegantly match an erased type in scala?

Is there any elegant way, to arrive from:
def foo[T: TypeTag](a: A[T]) {
// can we match on the type of T here?
}
at a match expression on the type of T?
Obviously this below does not overcome erasure for T, so must we inspect the TypeTag by hand?
a match {
case _:A[SomeSpecificType] => ...
Or does scala afford some elegance to that end?
Sadly no, as the compiler does not take type tags into account if you add type checks to a pattern. I'm not sure why and whether this is planned. You can however compare type tags for equality:
typeOf[T] =:= typeOf[List[String]]
You can use that in an if or match condition and then cast to the target type.
After thinking a bit more about it, I recognized that it would be quite easy to write my own pattern extractor, that hides the check and cast:
import scala.reflect.runtime.universe._
class TypeTest[A: TypeTag]() {
def unapply[B: TypeTag](v: B): Option[A] =
if(typeOf[B] <:< typeOf[A])
Some(v.asInstanceOf[A])
else
None
}
object TypeTest {
def apply[A: TypeTag] = new TypeTest()
}
Now, we can do stuff like this:
def printIfStrings[T: TypeTag](v: T) {
val string = TypeTest[List[String]]
v match {
case string(s) => printString(s)
case _ =>
}
}
def printString(s: List[String]) {
println(s)
}
printIfStrings(List(123))
printIfStrings(List("asd"))
This is already quite neat, but as Scala does not support passing an argument directly to an extractor in a pattern, we have to define all extractors as val string before the match expression.
Macros
Macros can transform code, so it should be easy enough to transform any unchecked typechecks in a match expression into an appropriate pattern or add explicit checks using the type tags directly.
This however requires that we have a macro invocation wrapped around every critical match expression, which would be quite ugly. An alternative is to replace match expressions by some method call that takes a partial function as an argument. This method can be provide for an arbitrary type using an implicit conversion.
The only remaining problem then is that the compiler typechecks the code before any macros are invoked, so it will generate a warning for the unchecked cast even though it is now checked. We can still us #unchecked to suppress these warnings.
I chose to replace type checks in patterns by the extractor described above instead of adding a condition to the case and explicit type casts. The reason for that is that this transformation is local (I just have to replace a subexpression with another).
So here is the macro:
import scala.language.experimental.macros
import scala.language.implicitConversions
import scala.reflect.macros.blackbox.Context
object Switch {
implicit class Conversion[A](val value: A) {
def switch[B](f: PartialFunction[A, B]): B = macro switchImpl
}
def switchImpl(c: Context)(f: c.Tree): c.Tree = {
import c.universe._
val types = collection.mutable.Map[Tree,String]()
val t1 = new Transformer {
override def transformCaseDefs(trees: List[CaseDef]) = {
val t2 = new Transformer {
override def transform(tree: Tree) = {
def pattern(v: String, t: Tree) = {
val check = types.getOrElseUpdate(t, c.freshName())
pq"${TermName(check)}(${TermName(v)})"
}
tree match {
case Bind(TermName(v),Typed(Ident(termNames.WILDCARD),
Annotated(Apply(
Select(New(Ident(TypeName("unchecked"))),
termNames.CONSTRUCTOR), List()
), t)))
=> pattern(v,t)
case Bind(TermName(v),Typed(Ident(termNames.WILDCARD),t))
=> pattern(v,t)
case _ => super.transform(tree)
}
}
}
t2.transformCaseDefs(trees)
}
}
val tree = t1.transform(c.untypecheck(f))
val checks =
for ((t,n) <- types.toList) yield
q"val ${TermName(n)} = Switch.TypeTest[$t]"
q"""
..$checks
$tree(${c.prefix}.value)
"""
}
import scala.reflect.runtime.universe._
class TypeTest[A: TypeTag]() {
def unapply[B: TypeTag](v: B): Option[A] =
if(typeOf[B] <:< typeOf[A]) Some(v.asInstanceOf[A])
else None
}
object TypeTest {
def apply[A: TypeTag] = new TypeTest()
}
}
And now magically type checks in patterns work:
import Switch.Conversion
val l = List("qwe")
def printIfStrings2[T: scala.reflect.runtime.universe.TypeTag](v: T) {
v switch {
case s: Int => println("int")
case s: List[String] #unchecked => printString(s)
case _ => println("none")
}
}
printIfStrings2(l)
printIfStrings2(List(1, 2, 3))
printIfStrings2(1)
I'm not sure whether I handle all possible cases correctly, but every thing I tried worked fine. A type with multiple annotations is possibly not handled correctly if it is also annotated by #unchecked, but I couldn't find an example in the standard library to test this.
If you leave out the #unchecked the result is exactly the same, but as mentioned above you will get a compiler warning. I don't see a way to get rid of that warning with normal macros. Maybe annotation macros can do it but they are not in the standard branch of Scala.

Pattern matching and (ereased) generic function type argument

Lets say I want to write generic function foo that will use pattern matching to check whether passed argument is of type of it's generic argument T
Naive attempt:
def foo[T]: PartialFunction[Any, Boolean] = {
case x: T =>
true
case _ =>
false
}
... won't work since T gets ereased. Compiller warning confirms that:
Warning:(11, 13) abstract type pattern T is unchecked since it is eliminated by erasure
case x: T =>
^
What is the best way to get it work?
Scala has introduced ClassTags for this purpose. They can be obtained by an implicit parameter, and will be automatically provided, which means you don't have to worry about the parameter when calling the method:
import scala.reflect.ClassTag
def foo[T](implicit tag: ClassTag[T]): PartialFunction[Any, Boolean] = {
case x: T =>
true
case _ =>
false
}
val isString = foo[String] // ClassTag gets provided implicitly here
isString("Hallo") // will return true
isString(42) // will return false
For further explanations see the docs.