Pattern Matching with Private Field - scala

Given:
scala> case class ParentPath(private val x: String) {
| val value = x.dropWhile(_ == '/')
| }
I can make a ParentPath:
scala> ParentPath("/foo")
res10: ParentPath = ParentPath(/foo)
I can't access its x (due to private, it appears).
scala> res10.
asInstanceOf canEqual copy isInstanceOf productArity productElement productIterator productPrefix toString value
I can get its value.
scala> res10.value
res11: String = foo
However, I'd prefer to return its value rather than x upon a pattern match:
scala> res10 match { case ParentPath(x) => x}
res13: String = /foo
How can I pattern match with value rather than x?
scala> ParentPath.unapply(res10)
res15: Option[String] = Some(/foo)
I tried to override ParentPath#unapply, but got a compile-time error:
scala> case class ParentPath(private val x: String) {
| val value = "foo"
| override def unapply(p: ParentPath): Option[String] = Some(value)
| }
<console>:15: error: method unapply overrides nothing
override def unapply(p: ParentPath): Option[String] = Some(value)
^

The unapply method belongs in the companion object, and you cannot override it for a case class, anyway. For a normal class, this will work. Or, if you simply use a differently named object that has an unapply method of the same signature.
class ParentPath(private val x: String) {
val value = "foo"
}
object ParentPath {
def unapply(p: ParentPath): Option[String] = Some(p.value)
}
scala> new ParentPath("/foo") match { case ParentPath(x) => x }
res1: String = foo

Related

In scala, how to pattern match against an inlined expression?

In scala, a pattern matching for a class has to be conducted in the following way:
val clz: Class[_] = ???
clz match {
case v if clz == classOf[String] =>
// do something
case v if clz == classOf[Int] =>
// do something
//...
}
The boilerplate code v if clz == is really redundant and I'd like to have them removed or reduced, since functions like classOf[String] and classOf[int] can be inlined and used like constant. So how can I do this?
There is some support, mostly in relation to array element types:
scala> import reflect.ClassTag
import reflect.ClassTag
scala> val c: Class[_] = classOf[Int]
c: Class[_] = int
scala> (ClassTag(c): Any) match { case ClassTag.Boolean => "bool" case ClassTag.Int => "int" }
res0: String = int
but the use case is to simplify type tests
scala> def f[A: ClassTag] = ("abc": Any) match { case _: A => "A" case _ => "other" }
f: [A](implicit evidence$1: scala.reflect.ClassTag[A])String
scala> f[Int]
res1: String = other
scala> f[String]
res2: String = A
Maybe one argument for classTag not looking like a stable id is that classOf[C] evaluated in different classloaders don't compare equal.

Scala: how to check whether a object is instance of Array

I want to check whether a obj in Scala is of type Array, not caring about whether what type of the values are inside. Is there some easy way to do this?
var x = Array(1,2,3)
x.isInstanceOf[Array[Any]] // which is false
I want it to be true.
Update:
I have a function:
def someFunction(obj: Any) {
if (obj.isInstanceOf[Int]) {
// do something
}
if (obj.isInstanceOf[String]) {
// do something
}
if (obj.isInstanceOf[Array[Any]) {
// for each of the obj inside the Array do something
}
}
array Array(1,2,3) is of type Int, so Array[Any] would weirdly return false only in case of Array collection.
If you don't care the type of Array, you can compare to Array[_] (array of whatever type)
scala> var x = Array(1,2,3)
x: Array[Int] = Array(1, 2, 3)
scala> x.isInstanceOf[Array[Int]]
res0: Boolean = true
scala> x.isInstanceOf[Array[_ <: Any]]
res7: Boolean = true
scala> x.isInstanceOf[Array[_ <: AnyVal]]
res12: Boolean = true
scala> x.isInstanceOf[Array[_]]
res13: Boolean = true
scala.Int extends AnyVal which extends Any you can explicitly mentions _ extends AnyVal.
But other scala collections like List[T] is instance of List[Any]
scala> List(1, 2).isInstanceOf[List[Any]]
res30: Boolean = true
scala> Seq(1, 2).isInstanceOf[Seq[Any]]
res33: Boolean = true
Also, List[T] is instance of Seq[Any], because List extends Seq, and T extends Any
scala> List(1, 2).isInstanceOf[Seq[Any]]
res35: Boolean = true
AND, for if else you can solve with pattern match way,
array match {
case x: Int => println("int")
case x: String => "string"
case Array[Int] => println("ints")
case Array[String] => println("strings")
case _ => println("whatever")
}
x.isInstanceOf[Array[_]]
use _ for container any type match. and for _ it's called existential type.
Document:
Underscore for existential type in Scala

no type parameters for method flatMap

I don't know why the following code can not compile, this is the error message:
Error:(29, 7) no type parameters for method flatMap: (f: String => Option[B])Option[B] exist so that it can be applied to arguments (String => Some[Class[?0]] forSome { type ?0 <: org.apache.hadoop.io.compress.CompressionCodec })
--- because ---
argument expression's type is not compatible with formal parameter type;
found : String => Some[Class[?0]] forSome { type ?0 <: org.apache.hadoop.io.compress.CompressionCodec }
required: String => Option[?B]
a.flatMap(codecClassName => {
^
and code
def f(a: Option[String]): Unit = {
a.flatMap(codecClassName => {
val codecFactory = new CompressionCodecFactory(new Configuration())
val codecClass = codecFactory.getCodecClassByName(codecClassName)
if (codecClass == null) {
throw new RuntimeException("Unknown or not supported codec:" + codecClassName)
}
Some(codecClass)
})
}
This seems to be related to the fact that getClass and classOf are not returning the exact same thing. See Scala equivalent of Java java.lang.Class<T> Object for more details.
Looking around for a workaround I came across Scala Getting class type from string representation.
So how about:
val codecClass = Manifest.classType(codecFactory.getCodecClassByName(codecClassName))
This should work. flatMap involves both map and flatten, so it may need more type annotations in some cases. The overall code works after annotation of the function parameter, i.e. (codecClassName: String).
Note the other change -- that flatMap with an inner function returning an Option type is the same as a map if that function returns what's inside the Option (i.e. flattens the option) (see below).
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.io.compress.{CompressionCodec, CompressionCodecFactory}
...
def f(a: Option[String]): Option[Class[_ <: CompressionCodec]] = {
a.map((codecClassName: String) => {
val codecFactory = new CompressionCodecFactory(new Configuration())
val codecClass = codecFactory.getCodecClassByName(codecClassName)
if (codecClass == null) {
throw new RuntimeException("Unknown or not supported codec:" + codecClassName)
}
codecClass
})
}
To show the relationship between flatMap and map as described above:
scala> val opt: Option[Int] = Some(1)
opt: Option[Int] = Some(1)
scala> opt.map((i: Int) => i + 1)
res0: Option[Int] = Some(2)
scala> val opt2: Option[Int] = None
opt2: Option[Int] = None
scala> opt.flatMap((i: Int) => Some(i + 1))
res1: Option[Int] = Some(2)
scala> opt2.map((i: Int) => i + 1)
res3: Option[Int] = None
scala> opt2.flatMap((i: Int) => Some(i + 1))
res2: Option[Int] = None

Parsing a String to Boolean or Int

To parse a string to an int we can do theString.toInt, and to a boolean theString.toBoolean. How can I make this generic?
I want to somehow parameterise a function so that I can try to parse the string as either a boolean or int, handle errors and return defaults on error, etc.
I've got this:
def tryParsing[T: TypeTag](value: String)(implicit errorAccumulator: Accumulator[Int]): Option[T] = {
// scala's .toBoolean only permits exactly "true" or "false", not numeric booleans.
val validBooleans = Map(
"true" -> true,
"false" -> false,
"1" -> true,
"0" -> false
)
import scala.reflect.runtime.universe._
// doesn't work. Also, using TypeTag doesn't seem to work.
typeOf[T] match {
case t if t <:< typeOf[Boolean] =>
val result = validBooleans.get(value.asInstanceOf[String].toLowerCase)
if (result.isEmpty) {
logger.warn(s"An error occurred parsing the boolean value `$value`")
errorAccumulator += 1
}
result.asInstanceOf[Option[T]]
case _ =>
Try(value.asInstanceOf[T]) match {
case Success(x) => Some(x: T)
case Failure(e) =>
logger.warn(s"An parsing error occurred: $e")
errorAccumulator += 1
None
}
}
}
I can't match on the type tag. I guess this is because if value was of type T then the typetag would prevent its type from being erased. But here, I want to call this like:
tryParsing[Boolean]("1") // value from variable
How can I match on types or otherwise do what I'm trying to do in scala 2.10?
Use the typeclass pattern:
trait Parser[T] {
def parse(input: String): Option[T]
}
def parse[T](input: String)(implicit parser: Parser[T]): Option[T] =
parser.parse(input)
import util.Try
implicit object IntParser extends Parser[Int] {
def parse(input: String) = Try(input.toInt).toOption
}
implicit object BooleanParser extends Parser[Boolean] {
def parse(input: String) = Try(input.toBoolean).toOption
}
Voila:
scala> parse[Int]("3")
res0: Option[Int] = Some(3)
scala> parse[Int]("zzz")
res1: Option[Int] = None
scala> parse[Boolean]("true")
res2: Option[Boolean] = Some(true)
scala> parse[Boolean]("zzz")
res3: Option[Boolean] = None

How to filter methods by return type with scala reflection?

I'm trying to test whether a method's return type exactly matches a supplied type.
Somehow, I've found two String Types that are not equal.
class VarAndValue {
#BeanProperty
val value = "";
}
class ScalaReflectionTest {
#Test
def myTest(): Unit = {
val type1 = universe.typeOf[String]
// Get return value of VarAndValue.getValue
val type2 = universe.typeOf[VarAndValue].
declarations.
filter { m => m.name.decoded == "getValue" && m.isMethod }.
head.
asInstanceOf[universe.MethodSymbol].
returnType
println(type1) // String
println(type2) // String
println(type1.getClass())
println(type2.getClass()) // !=type1.getClass() !!
println(type1==type2) // False
}
}
yields...
String
String
class scala.reflect.internal.Types$TypeRef$$anon$3
class scala.reflect.internal.Types$TypeRef$$anon$6
false
How can I filter methods of a class by their return type? (It seems very difficult if I can test for equality of the return types).
Scala 2.10
UPDATE:
I can't drop into the Java reflection universe because this erased type information for generics like List[Int] (which become List[Object] is java-land where they're really List[java.lang.Integer]). I need my matched to pay attention to the generic parameter information that the scala type universe preserves.
Use =:= to compare types.
scala> import beans._
import beans._
scala> :pa
// Entering paste mode (ctrl-D to finish)
class VarAndValue {
#BeanProperty
val value = "";
}
// Exiting paste mode, now interpreting.
defined class VarAndValue
scala> import reflect.runtime._, universe._
import reflect.runtime._
import universe._
scala> val str = typeOf[String]
str: reflect.runtime.universe.Type = String
scala> val ms = typeOf[VarAndValue].declarations filter (m => m.isMethod && m.name.decoded == "getValue")
warning: there were two deprecation warnings; re-run with -deprecation for details
ms: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(method getValue)
scala> val mm = ms.toList
mm: List[reflect.runtime.universe.Symbol] = List(method getValue)
scala> val m = mm.head.asInstanceOf[MethodSymbol]
m: reflect.runtime.universe.MethodSymbol = method getValue
scala> val t = m.returnType
t: reflect.runtime.universe.Type = java.lang.String
scala> println(t)
java.lang.String
scala> println(str)
String
scala> str == t
res2: Boolean = false
scala> str match { case `t` => }
scala.MatchError: String (of class scala.reflect.internal.Types$AliasNoArgsTypeRef)
... 33 elided
scala> str =:= t
res4: Boolean = true
scala> str match { case TypeRef(a,b,c) => (a,b,c) }
res5: (reflect.runtime.universe.Type, reflect.runtime.universe.Symbol, List[reflect.runtime.universe.Type]) = (scala.Predef.type,type String,List())
scala> t match { case TypeRef(a,b,c) => (a,b,c) }
res6: (reflect.runtime.universe.Type, reflect.runtime.universe.Symbol, List[reflect.runtime.universe.Type]) = (java.lang.type,class String,List())
Depending on what you're going for, consider that conforming types can have differing representations:
scala> typeOf[List[Int]]
res11: reflect.runtime.universe.Type = scala.List[Int]
scala> type X = List[Int]
defined type alias X
scala> typeOf[X].dealias
res12: reflect.runtime.universe.Type = List[scala.Int]
scala> res11 =:= res12
res13: Boolean = true
scala> res11 == res12
res14: Boolean = false
scala> typeOf[X] <:< res11
res15: Boolean = true
scala> typeOf[X] =:= res11
res16: Boolean = true
Turns out this is the way to compare types ...
type1 match {
case type2 => true
case _ => false
}
which gives a different answer than type1==type.
Scala is a strange beast.