I want to write a method that returns true if an Option[Int] contains a specific value and false otherwise. What is the idiomatic way of doing this?
var trueIf5(intOption: Option[Int]): Boolean {
intOption match {
case Some(i) => i == 5
case None => false
}
}
This above solution clearly works, but the Scala docs label this approach as less-idiomatic.
Is there some way I can do the same thing using map, filter, or something else?
I got this far, but it only changes the problem to "Return true if Option contains true", which is effectively the same as "Return true if Option contains 5".
var trueIf5(intOption: Option[Int]): Boolean {
intOption.map(i => i == 5).???
}
Since you're testing whether it contains a value:
scala> Some(42) contains 42
res0: Boolean = true
Don't neglect your -Xlint:
scala> Option(42).contains("")
res0: Boolean = false
scala> :replay -Xlint
Replaying: Option(42).contains("")
<console>:12: warning: a type was inferred to be `Any`; this may indicate a programming error.
Option(42).contains("")
^
res0: Boolean = false
Those built-in warnings aren't as effective with universal equality:
scala> Option(42).exists("" == _) // no warning
res1: Boolean = false
intOption.exists(_ == 5)
The doc
Why has no one suggested:
intOption == Some(5)
Related
I think Scala is the first language I've come across where the following doesn't work:
true + true
// Name: Compile Error
// Message: <console>:32: error: type mismatch;
// found : Boolean(true)
// required: String
// true + true
// ^
// StackTrace:
Can someone explain this error? Why on earth are Strings getting involved?
Also, what is the canonical way to accumulate Boolean values in Scala? Do I need to convert them to Int / is there a way to overload + for it to work as expected?
The reason "String" is getting involved is the implicit conversion from Boolean to String which allows writing expressions like "text " + true (which evaluates to text true).
You can create a similar implicit conversions from Boolean to Int, as suggested in here:
implicit def bool2int(b:Boolean) = if (b) 1 else 0
Do note that now you'll have two implicit conversions from Boolean, which might get a bit tricky:
// without bool2int implicit conversion:
scala> true + true
<console>:12: error: type mismatch;
found : Boolean(true)
required: String
true + true
^
// conversion to String works:
scala> true + " text"
res1: String = true text
scala> "text " + true
res2: String = text true
// now we add bool2int:
scala> implicit def bool2int(b:Boolean) = if (b) 1 else 0
bool2int: (b: Boolean)Int
// which makes this work:
scala> true + true
res3: Int = 2
// BUT! now this conversion will be picked up because Int has a `+` method:
scala> true + " text"
res4: String = 1 text // probably not what we intended!
// This would still work as before:
scala> "text " + true
res5: String = text true
You can use implicit conversions. When the compiler find the expression is of wrong type, it will look for an implicit function.
On creating the implicit function, the compiler will call it each time when Boolean is found but Int is required in the context.
import scala.language.implicitConversions
implicit def toInt(v:Boolean):Int = if (v) 1 else 0
To see how it works, let's add a print statement
implicit def toInt(v:Boolean):Int = {
println (s"Value: $v")
if (v) 1 else 0
}
Output:
scala> val x = false
x: Boolean = false
scala> val y = true
y: Boolean = true
scala> x
res6: Boolean = false // No implicit function called.
scala> x + y
Value: false // Implicit function called for x.
Value: true // Implicit function called for y.
res5: Int = 1
So this function is called when Boolean is found and Int is required in the context, but not otherwise.
In addition to implicit conversion, you can also convert the boolean to a wrapped type which supplies an addition operator.
class WrappedBoolean(bool: Boolean) {
val value = if (bool) 1 else 0
def +(other: Boolean) = (if (other) 1 else 0) + value
}
implicit def boolean2WrappedBoolean(bool: Boolean) = new WrappedBoolean(bool)
I have a List called
val types : List[runtime.universe.Type]
Now I want to match the types(j) with Option of any type.
Like this,
if(types(j) =:= typeOf[Option[AnyVal]]) {
I tried
typeOf[Option[_]], typeOf[Option[Any]]
But none of these are matching.
How to match?
=:= matches only when the two type are equivalent, and, e.g. Option[String] and Option[Any] are not equivalent.
You should use <:< instead:
if(types(j) <:< typeOf[Option[Any]]) {
You can use the typeSymbol to match an Option with any type. You can also just use == on a type if you want an exact match like just matching on Option[Any]
import scala.reflect.runtime.{universe => ru}
val types = List(ru.typeOf[Option[String]],
ru.typeOf[Option[Any]],
ru.typeOf[String])
// matches any Option and prints true true false
types.foreach(t => println(t.typeSymbol == ru.typeOf[Option[_]].typeSymbol))
// matches only Option[Any] and prints false true false
types.foreach(t => println(t == ru.typeOf[Option[Any]]))
Reading this, I still have questions about unapply() that returns Boolean.
If take a look at Scala Programming Book (2nd edition), page 602. There is an example:
case Email(Twice(x # UpperCase()), domain) => ...
Where UpperCase defined as an object that has unapply() returning Boolean and does not have apply()
object UpperCase {
def unapply(s:String): Boolean = s.toUpperCase == s
}
Where Twice is something like this:
object Twice {
def apply(s:String): String = s + s
...
The questions are (must be too many, sorry for that):
How does UpperCase().unapply(..) works here?
If I pass: DIDI#hotmail.com, then x in first code snippet = 'DI'.. then we use '#' ..to bind 'x' to pass it to UpperCase.unapply to invoke unapply(x) i.e unapply('DIDI') (?) Then it returns True.
But why not Option ? I tend to think that unapply returns Option.. kind of one way how it works. That's probably because usually Option wraps some data, but for simple case we should NOT wrap boolean? And because we do not have apply()?
What the difference, when use Boolean / Option ? Based on this example.
And this syntax: x # UpperCase(), is it supposed to substitute value match case (is that way how I suppose to read it?) syntax if we are matching inside one particular case? It doesn't seems as unified way/syntax of doing this.
Usually syntax like (assuming that x,y is Int): case AA(x # myX, y) => println("myX: " + myX) says that x binds to myX, basically myX is alias to x.. in this case. But in our case - x # UpperCase(). x binds to UpperCase().unapply().. putting x as parameter. I mean binding here is quite abstract/wide notion..
This is simple:
1) If you return Boolean, your unapply just tests matching query
scala> object UpperCase {
| def unapply(s: String) = s.toUpperCase == s
| }
defined module UpperCase
scala> "foo" match {
| case UpperCase() => true
| case _ => false
| }
res9: Boolean = false
2) If you return Option[T], you create an extractor, which unwraps T
scala> object IsUpperCase {
| def unapply(s: String) = Option(s).map(x => x.toUpperCase == x)
| }
defined module IsUpperCase
scala> "FOO" match {case IsUpperCase(flag) => flag}
res0: Boolean = true
This is not so simple.
The behavior of "boolean test" match just changed in the latest milestone:
apm#mara:~/clones/scala$ ./build/pack/bin/scala
Welcome to Scala version 2.11.0-20130911-042842-a49b4b6375 (OpenJDK 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.
scala>
scala> object OK { def unapply(s: String) = Some(s) filter (_ == "OK") }
defined object OK
scala> import PartialFunction._
import PartialFunction._
scala> cond("OK") { case OK() => true }
<console>:12: error: wrong number of patterns for object OK offering String: expected 1, found 0
cond("OK") { case OK() => true }
^
<console>:12: error: wrong number of patterns for object OK offering String: expected 1, found 0
cond("OK") { case OK() => true }
^
scala> cond("OK") { case OK(x) => true }
res1: Boolean = true
scala> :q
Previously, you could use the extractor without extracting any fields, just for a "boolean test", even though the result of the unapply is not Boolean:
apm#mara:~/clones/scala$ scalam
Welcome to Scala version 2.11.0-M4 (OpenJDK 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import PartialFunction._
import PartialFunction._
scala> object OK { def unapply(s: String) = Some(s) filter (_ == "OK") }
defined object OK
scala> cond("OK") { case OK() => true }
res0: Boolean = true
scala> cond("OK") { case OK(x) => true }
res1: Boolean = true
Here is some discussion and here is the change in the way extractor signatures are processed.
In my Scala program, I am receiving some JSON.
One of the fields is an optional Boolean. If the field is missing, or if its value is false, I would like to return None. If its value is true, I would like to return Some(true).
SInce this is equivalent to converting Some(false) into None, I have defined the following function:
def boolmap(ob: Option[Boolean]) = if(ob == Some(false)) None else ob
It works, but it doesn't seem to be very idiomatic. Is there anything more elegant?
This is ob.filter(identity). I'm not sure whether that's clearer, but it's shorter.
I agree with others that you might as well just return true or false since you aren't differentiating between the attribute not being there at all, being null or being false.
If you just returned Boolean you could do it this way:
scala> Some(true) exists { _ == true }
res0: true
scala> Some(false) exists { _ == true }
res1: Boolean = false
scala> None exists { _ == true }
res2: Boolean = false
If you insist on returning Option[Boolean] a pattern match would be more idiomatic:
ob match {
case Some(true) => Some(true)
case _ => None
}
You could also use collect but in this case it would look IMO weird:
obj collect { case true => true }
I am beginning Scala and I don't understand what the s => part is/does. Could someone explain me that?
thrill.remove(s => s.length == 4)
It's a way of specifying a function. A function is something that takes one or more parameters as input and gives back an output. One of the ways you can specify a function is with the => symbol.
s: String => s.length == 4 // a function that takes a String called s as input
// and returns a Boolean (true if the length of s is 4
// false otherwise)
In scala you can use functions like you use integer or strings or any other kind of basic data types.
You can assign them to variables:
scala> val f = (s: String) => s.length==4 // assigning our function to f
f: String => Boolean = <function1>
scala> f("abcd") // ...and using it
res1: Boolean = true
and you can pass them as parameters to other functions or methods:
scala> val thrill = List("foo", "bar", "baz", "bazz")
thrill: List[java.lang.String] = List(foo, bar, baz, bazz)
scala> thrill.remove(s => s.length == 4)
warning: there were 1 deprecation warnings; re-run with -deprecation for detail
res2: List[java.lang.String] = List(foo, bar, baz)
here you're saying to the remove method: "apply this function s => s.length==4 to each element in the list, and remove all elements where that function returns true"
By the way, notice that remove is deprecated. The suggested alternative is filterNot
scala> thrill.filterNot(s => s.length == 4)
res3: List[java.lang.String] = List(foo, bar, baz)
The expression
s => s.length == 4
represents a function which takes a string (I'm guessing) and returns a boolean value based on whether it has length four
val f = s => s.length == 4
println(f("five")) //prints "true"
println(f("six")) //prints "false"
the s => part just declares the parameter names for the function (in this case, just one: s)
This says "run the function s => s.length == 4 over all items in thrill, and remove any where the function returns true." Logically, that function must take a single item of the type contained in thrill as a parameter, and it must return a boolean (true or false).
The scala syntax s => ... indicates a lambda function- a kind of shorthand function where in many cases the function's parameter and return types are inferred. For example in this case the compiler is smart enough to know that if thrill contains Strings, s must be a string. Likewise, it can confirm in a statically typed way that the return value (s.length == 4) is a boolean, and satisfies the requirement for a boolean return value.
In short: think of it as a function defined as boolean f(String s) { return s.length == 4; }
I believe all of the following are the same as each other (although I'm a Scala newb too, feel free to offer corrections)
thrill.remove((s:String) => s.length == 4)
thrill.remove(s => s.length == 4)
thrill.remove(_.length == 4)