How to create PartialFunction literal after 2.12.5? - scala

Since PartialFunction.apply is deprecated since Scala 2.12.5, how can I create a PartialFunction without declaring a new variable?E.g. I was able to do:
List(0).map(PartialFunction[Int,Int]{
case 0 => 100
case x => x*100
}.orElse{
case 100 => 0
})
How to write the same thing in Scala 2.12.5 in one statement?

The deprecation warning actually tells you what to do: "use an explicit type annotation instead":
val f = ({ case 0 => 100; case x => x * 100 }: PartialFunction[Int, Int])
.orElse[Int, Int]{ case 100 => 0 }
Update
Why the apply was deprecated (probably):
val pf = PartialFunction[Int, Int]{ case 100 => 42 }
pf.isDefinedAt(50)
// res2: Boolean = true
The problem is: it's a partial function that is implicitly cast into normal function, and then again wrapped into partial function. It completely loses all the information about where it is actually defined, so isDefinedAt returns true for all inputs.

Related

scala: anonymous partial function strange syntax

I came across a code similar to this, and it was surprised that it even compiles:
scala> val halfSize: PartialFunction[String, Int] = _.length match {
case even if even % 2 == 0 => even / 2
}
halfSize: PartialFunction[String,Int] = <function1>
scala> List("x", "xx").collect(halfSize)
res1: List[Int] = List(1)
As far as I known, the valid syntax to define a PartialFunction is a case function:
val halfSize: PartialFunction[String, Int] = {
case s if s.length % 2 == 0 => s.length / 2
}
The first code seems more optimized since it calls length only once. But even in the SLS I was not able to find the explanation of the syntax. Is this an undocumented feature of scalac ?
The rules are given in https://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#anonymous-functions:
The eventual run-time value of an anonymous function is determined by the expected type:
...
PartialFunction[T, U], if the function literal is of the shape x => x match { … }
In this case the literal does have such a shape, as rogue-one's answer explains, so PartialFunction is allowed as the expected type.
(EDIT: actually, it doesn't, since it matches x.length instead of x. This looks like a minor bug, but one which should be fixed by changing the specification.)
A PartialFunction's value receives an additional isDefinedAt member, which is derived from the pattern match in the function literal, with each case's body being replaced by true, and an added default (if none was given) that evaluates to false.
So in this case it ends up with
def isDefinedAt(x: String) = x.length match {
case even if even % 2 == 0 => true
case _ => false
}
val halfSize: PartialFunction[String, Int] = _.length match {
case even if even % 2 == 0 => even / 2
}
The underscore (_) in the above function is just a short hand notation that refers to the single argument of the function. Thus the above snippet is just a short form of
val halfSize: PartialFunction[String, Int] = { (x: String) => x.length match {
case even if even % 2 == 0 => even / 2
}
}

Default empty case for varargs

Say you wish to use pattern matching when calling a method with varargs like so:
def foo(bar: Int*) = ???
val x = false
foo(x match {
case true => 1
case _ =>
})
Running the above code results in type mismatch error, since foo requires an argument of type Int but found Unit instead in the default case. Removing the default case, on the other hand, results in a warning that the match may not be exhaustive, and rightfully so.
My question is, how do I supply an empty default case for the match (which would result in calling foo() without any arguments)?
You could capture the match result in a sequence and represent the lack of arguments as an empty one. Then just splat the result into the parameter:
val x = true
foo((x match {
case true => Seq(1)
case _ => Seq.empty
}):_*)
One option would be to use an Option[Int] instead of an Int:
def foo(bar: Option[Int]*) = ???
val x = false
foo(x match {
case true => Some(1)
case _ => None
})
I think an if-else expression would be less verbose here:
foo(if (x) Some(1) else None)
I'd argue though that if you're matching over a single Boolean there's no point in passing varargs at all.

IntelliJ IDEA: Detects comparisons (== and !=) of expressions which cannot be the same type

I use a Scala plugin for IntelliJ IDEA, and I have found a weird behaviour of that plugin. Let me show you a code snippet:
def fun: Option[Any] => Int = {
case Some(x) if x.isInstanceOf[Int] => x.asInstanceOf[Int]
case None => 0
}
Regarding the Scala code, IDEA gives me a warning:
Comparing unrelated types
Detects comparisons (== and !=) of expressions which cannot be the same type
and it highlights the next statement x.isInstanceOf[Int]. I use isInstanceOf operator just to determine a type of x. Is this a bug of the plugin or I missed something in Scala syntax?
Use getOrElse(0) for this operation.
Edit :
You are geting this error as Some(x) is not same as Int.
But you are making condition direct over here as Some(x) first and then directly checking whether the instance is of Int,so they are basically not of same type(Int and Some)
case Some(x) if x.isInstanceOf[Int] => x.asInstanceOf[Int]
To avoid this warning:
You can do something like this if you want to keep it as Option[Any] as Input.
def fun(x:Option[Any]):Int = x match {
case x:Some[Int] => x.get
case x => 0
}
Otherwise,if you know that input will be Option[Int] then
use it as parameter.
def fun(x:Option[Int]):Int = x match {
case x:Some[Int] => x.get
case None => 0
}
I do not get a similar warning, but something very important you should be aware of is that your code is not "case statement" complete and has potential holes. Should you pass it Some("String") for example, none of your case lines can handle this. Potential fixes:
def fun: Option[Any] => Int = {
case Some(x) => if (x.isInstanceOf[Int]) x.asInstanceOf[Int] else 0
case None => 0
}
or
def fun: Option[Any] => Int = {
case Some(x) if x.isInstanceOf[Int] => x.asInstanceOf[Int]
case Some(other) => 0
case None => 0
}

How is a match word omitted in Scala?

In Scala, you can do
list.filter { item =>
item match {
case Some(foo) => foo.bar > 0
}
}
But you can also do the quicker way by omitting match:
list.filter {
case Some(foo) => foo.bar > 0
}
How is this supported in Scala? Is this new in 2.9? I have been looking for it, and I can figure out what makes this possible. Is it just part of the Scala compiler?
Edit: parts of this answer are wrong; please refer to huynhjl's answer.
If you omit the match, you signal the compiler that you are defining a partial function. A partial function is a function that is not defined for every input value. For instance, your filter function is only defined for values of type Some[A] (for your custom type A).
PartialFunctions throw a MatchError when you try to apply them where they are not defined. Therefore, you should make sure, when you pass a PartialFunction where a regular Function is defined, that your partial function will never be called with an unhanded argument. Such a mechanism is very useful e.g. for unpacking tuples in a collection:
val tupleSeq: Seq[(Int, Int)] = // ...
val sums = tupleSeq.map { case (i1, i2) => i1 + i2 }
APIs which ask for a partial function, like the collect filter-like operation on collections, usually call isDefinedAt before applying the partial function. There, it is safe (and often wanted) to have a partial function that is not defined for every input value.
So you see that although the syntax is close to that of a match, it is actually quite a different thing we're dealing with.
The language specification addresses that in section 8.5. The relevant portions:
An anonymous function can be defined by a sequence of cases
{ case p1 => b1 ... case pn => bn }
If the expected type is scala.Functionk[S1, ..., Sk, R] , the expression is taken to
be equivalent to the anonymous function:
(x1 : S1, ..., xk : Sk) => (x1, ..., xk) match {
case p1 => b1 ... case pn => bn
}
If the expected type is scala.PartialFunction[S, R], the expression is taken to
be equivalent to the following instance creation expression:
new scala.PartialFunction[S, T ] {
def apply(x: S): T = x match {
case p1 => b1 ... case pn => bn
}
def isDefinedAt(x: S): Boolean = {
case p1 => true ... case pn => true
case _ => false
}
}
So typing the expression as PartialFunction or a Function influences how the expression is compiled.
Also trait PartialFunction [-A, +B] extends (A) ⇒ B so a partial function PartialFunction[A,B] is also a Function[A,B].
-- Revised post --
Hmm, I'm not sure I see a difference, Scala 2.9.1.RC3,
val f: PartialFunction[Int, Int] = { case 2 => 3 }
f.isDefinedAt(1) // evaluates to false
f.isDefinedAt(2) // evaluates to true
f(1) // match error
val g: PartialFunction[Int, Int] = x => x match { case 2 => 3 }
g.isDefinedAt(1) // evaluates to false
g.isDefinedAt(2) // evaluates to true
g(1) // match error
It seems f and g behave exactly the same as PartialFunctions.
Here's another example demonstrating the equivalence:
Seq(1, "a").collect(x => x match { case s: String => s }) // evaluates to Seq(a)
Even more interesting:
// this compiles
val g: PartialFunction[Int, Int] = (x: Int) => {x match { case 2 => 3 }}
// this fails; found Function[Int, Int], required PartialFunction[Int, Int]
val g: PartialFunction[Int, Int] = (x: Int) => {(); x match { case 2 => 3 }}
So there's some special casing at the compiler level to convert between x => x match {...} and just {...}.
Update. After reading the language spec, this seems like a bug to me. I filed SI-4940 in the bug tracker.

PartialFunction type

in scala play framework I seen this code:
abstract class AnalyserInfo
case class ColumnC(typeName:String,fieldName:String) extends AnalyserInfo
case class TableC(typeName:String) extends AnalyserInfo
val asIs :PartialFunction[AnalyserInfo,String] = {
case ColumnC(_,f) => f;
case TableC(typeName) => typeName
}
What is the difference with:
val asIs: (AnaliserInfo)=>String = (info) => info match {
case ColumnC(_,f) => f;
case TableC(typeName) => typeName
}
There is a preferred style? and why in the first case the match keyword can be omitted?
Thank you for the support.
Double => Double is just a shorthand for Function[Double, Double]. PartialFunction inherits from Function but adds a few methods. Most importantly, it adds the method isDefinedAt which allows you to query if the function is defined for some parameter.
The cases without a match are a special syntax to define partial functions, which generates an isDefinedAt that returns true for all matching cases.
Say we have a function that returns 1/x, but only for positive values of x, we could it define as:
scala> val f: (Double => Double) = { case x if x > 0 => 1/x }
f: (Double) => Double = <function1>
or as:
scala> val g: PartialFunction[Double, Double] = { case x if x > 0 => 1/x }
g: PartialFunction[Double,Double] = <function1>
The second version has the benefit that we could check if the function is applicable to some parameter:
scala> g.isDefinedAt(-3)
res0: Boolean = false
This feature is for example used in Scala to implement the actor library where an Actor might only consume certain types of messages.