When working in Scala, I often want to parse a field of type [A] and convert it to a Option[A], with a single case (for example, "NA" or "") being converted to None, and the other cases being wrapped in some.
Right now, I'm using the following matching syntax.
match {
case "" => None
case s: String => Some(s)
}
// converts an empty String to None, and otherwise wraps it in a Some.
Is there any more concise / idiomatic way to write this?
There are a more concise ways. One of:
Option(x).filter(_ != "")
Option(x).filterNot(_ == "")
will do the trick, though it's a bit less efficient since it creates an Option and then may throw it away.
If you do this a lot, you probably want to create an extension method (or just a method, if you don't mind having the method name first):
implicit class ToOptionWithDefault[A](private val underlying: A) extends AnyVal {
def optNot(not: A) = if (underlying == not) None else Some(underlying)
}
Now you can
scala> 47.toString optNot ""
res1: Option[String] = Some(47)
(And, of course, you can always create a method whose body is your match solution, or an equivalent one with if, so you can reuse it for that particular case.)
I'd probably use filterNot here:
scala> Option("hey").filterNot(_ == "NA")
res0: Option[String] = Some(hey)
scala> Option("NA").filterNot(_ == "NA")
res1: Option[String] = None
It requires you to think of Option as a collection with one or zero elements, but if you get into that habit it's reasonably clear.
A simple and intuitive approach includes this expression,
if (s.isEmpty) None else Some(s)
This assumes s labels the value to be otherwise matched (thanks to #RexKerr for the note).
Related
I wrote the following use case in scala:
val wordShortcut = Map("volume" -> "vol", "report" -> "rpt", ...)
object WordShortcutCase {
def unapply(key: String): Option[String] = wordShortcut.get(key)
}
val pluralR = "(.+)s".r
def encodeToken(token: String) = token match {
case WordShortcutCase(short) => short
case pluralR(singular) => singular
case _ => token
}
if scala Map would implement unapply, I wouldn't need the extra WordShortcutCase object (i could use case wordShortcut(short) => short instead`). This seems a common pattern to me.
And so the question is why scala Map does not implement the unapply method?
Map doesn't implement unapply because there is no sensible implementation that has the same characteristics as other collections.
In particular, you seem to want apply and unapply to do basically the same thing. But that's not how other collections work; they bind variables to contents and expect that the list is exhaustive (in the absence of a binding to "the rest"):
val xs = List("fish")
val ys = List("fish", "dish")
def iam(zs: List[String]) = zs match {
case List(x) => println(s"I am a $x")
case _ => println("Who am I??")
}
iam(xs) // Prints 'I am a fish'
iam(ys) // Prints 'Who am I??'
If Map were not a collection it would be free to implement unapply as another way to do an apply, more like regex does (though there, note that the key feature is being able to bind multiple variables to parts of the regex match). But since it is, having a regex-like unapply would be highly confusing because of the difference from other collections; and because maps are unordered and unapplySeq is ordered, having the same unapply as other collections would also be confusing. So it just doesn't have one.
This question already has an answer here:
Best practice for null-checking in Scala
(1 answer)
Closed 6 years ago.
I have call in Scala code which give Java Double type which can be null how can I check between null and non-null value in Scala code?
val myJavaDoubleValue: Double = thirdpartyCall.collectValue()
if(myJavaDoubleValue == null) {
println("Is NULL")
} else {
println("Is NOT NULL")
}
Any suggestion on doing this in Scala way?
Use an Option:
val myJavaDoubleValue: Option[Double] = Option(thirdpartyCall.collectValue())
The above will result in None if the result is null, otherwise in Some(actualValue).
See Option.apply()
Scala supports null in the same way as Java. So your code is syntatically correct.
However, a more modern approach would be to make sure your code almost never can touch null values. In order to do that, one possible way is using Scala Option class. An Option[T] is an value that may or may not be defined. A defined option is represented by Some[T], while a non-defined option is represented by None.
Option(thirdpartyCall.collectValue()) will return a Option[Double]. There are multiple ways to check the value contained in an Option, one of the Scala-idiomatic ways to perform what you want to do is pattern matching:
Option(thirdpartyCall.collectValue()) match {
case Some(value) =>
println(s"value is defined: $value")
case None =>
println("value is not defined")
}
However, Option is much more powerful than that. It supports methods like map, flatMap and fold which allow you to be even more expressive, for example:
def optionIsDefined[A](a: A) = Option(a).fold("not defined") { value => s"defined with value: $value" }
scala> optionIsDefined(42)
res2: String = defined with value: 42
scala> optionIsDefined(null)
res3: String = not defined
This is a great newcomers' friendly guide on Option.
In Scala, when I want to set something to None, I have a couple of choices: using None or Option.empty[A].
Should I just pick one and use it consistently, or are there times when I should be using one over the other?
Example:
scala> def f(str: Option[String]) = str
f: (str: Option[String])Option[String]
scala> f(None)
res0: Option[String] = None
scala> f(Option.empty)
res1: Option[String] = None
I would stick to None whenever possible, which is almost always. It is shorter and widely used. Option.empty allows you to specify the type of underlying value, so use it when you need to help type inference. If the type is already known for the compiler None would work as expected, however while defining new variable
var a = None
would cause infering a as None.type which is unlikely what you wanted.
You can then use one of the couple ways to help infer what you need
# var a = Option.empty[String]
a: Option[String] = None
# var a: Option[String] = None
a: Option[String] = None
# var a = None: Option[String] // this one is rather uncommon
a: Option[String] = None
Another place when compiler would need help:
List(1, 2, 3).foldLeft(Option.empty[String])((a, e) => a.map(s => s + e.toString))
(Code makes no sense but just as an example) If you were to omit the type, or replace it with None the type of accumulator would be infered to Option[Nothing] and None.type respectively.
And for me personally this is the place I would go with Option.empty, for other cases I stick with None whenever possible.
Short answer use None if talking about a value for example when passing parameter to any function, use Option.empty[T] when defining something.
var something = Option.empty[String] means something is None for now but can become Some("hede") in the future. On the other hand var something = None means nothing. you can't reassign it with Some("hede") compiler will be angry:
found : Some[String]
required: None.type
So, this means None and Option.empty[T] are not alternatives. You can pass None to any Option[T] but you can't pass Some[T] to None.type
Given that Option[A].empty simply returns None:
/** An Option factory which returns `None` in a manner consistent with
* the collections hierarchy.
*/
def empty[A] : Option[A] = None
I'd say:
As you said, be consistent throughout the codebase. Making it consistent would mean that programmers entrying your codebase have one less thing to worry about. "Should I use None or Option.empty? Well, I see #cdmckay is using X throughout the call base, I'll use that as well"
Readability - think what conveys the point you want the most. If you were to read a particular method, would it make more sense to you if it returned an empty Option (let's disregard for a moment the fact that the underlying implementation is simply returning None) or an explicit None? IMO, I think of None as a non-existent value, as the documentation specifies:
/** This case object represents non-existent values.
*
* #author Martin Odersky
* #version 1.0, 16/07/2003
*/
Following are worksheet exports using Scala and Scalaz .
def f(str: Option[String]) = str //> f: (str: Option[String])Option[String]
f(None) //> res1: Option[String] = None
var x:Option[String]=None //> x : Option[String] = None
x=Some("test")
x //> res2: Option[String] = Some(test)
x=None
x
Now using Scalaz ,
def fz(str: Option[String]) = str //> fz: (str: Option[String])Option[String]
fz(none) //> res4: Option[String] = None
var xz:Option[String]=none //> xz : Option[String] = None
xz=some("test")
xz //> res5: Option[String] = Some(test)
xz=none
xz
Note that all the statements evaluate in the same way irrespective of you use None or Option.Empty. How ?
As you can see it is important to let Scala know of your intentions via the return type in the var x:Option[String]=None statement. This allows a later assignment of a Some. However a simple var x=None will fail in later lines because this will make the variable x resolve to None.type and not Option[T].
I would think that one should follow the convention. For assignments i would go for the var x:Option[String]=None option. Also whenever using None it is good to use a return type (in this case Option[String]) so that the assignment does not resolve to None.type.
Only in cases where i have no way to provide a type and i need some assignment done will i go for Option.empty
As everyone else pointed out, it's more a matter of personal taste, in which most of the people prefer None, or, in some cases, you explicitly need to put the type because the compiler can't infer.
This question can be extrapolated to other Scala classes, such as Sequences, Map, Set, List and so on. In all of them you have several ways to define empty state. Using sequence:
Seq()
Seq.empty
Seq.empty[Type]
From the 3, I prefer the second, because:
The first (Seq()) is error prone. It looks like if someone wanted to create a sequence and forgot to add the elements
The second (Seq.empty) is explicit about the desire of having an empty sequence
While the third (Seq.empty[Type]) is as explicit as the second, it is more verbose, so I don't use typically
Is it good style in Scala to "abuse" the unapply method for pattern matching? What I wanted to do, is matching an object against another, and constructing the other object. Since I am fairly new in Scala, I wound up with the following solution. But it doesnt seem really right to use the unapply methode like this, since it is intended as an extractor. Could someone please give me feedback on this?
object Poker {
def unapply(hand: Hand): Option[Poker] = if(hand.countValueGroups().exists(_._2 == 4)) Some(new Poker(hand)) else None
}
val h = Hand("AC As AH Ad 2h")
h match {
case Poker(han) => println("POKER!!!"+han)
case _ => println("?????")
}
I don't know why this should be bad practice, so I'd say the answer is no, this is normal practice. As one commenter said, the mere purpose of unapply is to be used in pattern matching. While pattern matching is mostly used with the companion object of a case class, the concept is deliberately open to other extractors (example: regular expressions).
The only thing that's weird in your example is to return Option[Poker] with Poker begin a singleton object. Since you can't do much with that, probably you want to use a Boolean instead:
object Poker {
def unapply(hand: Hand): Boolean =
hand.countValueGroups().exists(_._2 == 4)
}
case class Hand(s: String) {
def countValueGroups(): List[(Any, Int)] = List("foo" -> 4) // ???
}
val h = Hand("AC As AH Ad 2h")
h match {
case Poker() => println("POKER!!!")
case _ => println("?????")
}
I am curious:
scala> Some(null) == None
res10: Boolean = false
Why isn't Some(null) transformed to None?
You should use Option(null) to reach the desired effect and return None.
Some(null) just creates a new Option with a defined value (hence Some) which is actually null, and there are few valid reasons to ever create one like this in real code.
Unfortunately, null is a valid value for any AnyRef type -- a consequence of Scala's interoperability with Java. So a method that takes an object of type A and, internally, store it inside an Option, might well need to store a null inside that option.
For example, let's say you have a method that takes the head of a list, checks if that head correspond to a key in a store, and then return true if it is. One might implement it like this:
def isFirstAcceptable(list: List[String], keys: Set[String]): Boolean =
list.headOption map keys getOrElse false
So, here's the thing... if the that inside list and keys come from some Java API, they both may well contain null! If Some(null) wasn't possible, then isFirstAcceptable(List[String](null), Set[String](null)) would return false instead of true.
I think the others in the thread do a good job explaining why Some(null) "should" exist, but if you happen to be getting Some(null) somewhere and want a quick way to turn it into None, I've done this before:
scala> val x: Option[String] = Some(null)
x: Option[String] = Some(null)
scala> x.flatMap(Option(_))
res8: Option[String] = None
And when the starting Option is a legit non-null value things work as you probably want:
scala> val y: Option[String] = Some("asdf")
y: Option[String] = Some(asdf)
scala> y.flatMap(Option(_))
res9: Option[String] = Some(asdf)
Much of Scala's WTFs can be attributed to its need for compatibility with Java. null is often used in Java as a value, indicating, perhaps the absence of a value. For example hashMap.get(key) will return null if the key is not matched.
With this in mind, consider the following possible values from wrapping a null returning method in an Option:
if (b) Some(hashMap.get(key)) else None
// becomes -->
None // the method was not invoked;
Some(value) // the method was invoked and a value returned; or
Some(null) // the method was invoked and null was returned.
Some(null) seems sufficiently distinct from None in this case to warrant allowing it in the language.
Of course if this is not desirable in your case then simply use:
if (b) Option(hashMap.get(key)) else None
// becomes -->
None // the method was not invoked or the mapped value was null; or
Some(value) // the method was invoked and a value returned
As a simple thought experiment, consider two lists of Strings, one of length 5 and one of length 20.
Because we're running on the JVM, it's possible to insert null as a valid element into one of these lists - so put that in the long list as element #10
What, then, should the difference be in the values returned from the two following expressions?
EDIT: Exchanged get for lift, I was thinking of maps...
shortList.lift(10) //this element doesn't exist
longList.lift(10) //this element exists, and contains null
Because Option is considered to be a Functor and being a Functor means:
Has unit function (apply or just Option("blah") in Scala)
Has map function which transforms value from T=>B but not a context
Obeys 2 Functor laws - identity law and associative law
In this topic the main part is #2 - Option(1).map(t=>null) can not transform context. Some should remain. Otherwise it brakes associative law!
Just consider the following laws example:
def identity[T](v: T) = v
def f1(v: String) = v.toUpperCase
def f2(v: String) = v + v
def fNull(v: String): String = null
val opt = Option("hello")
//identity law
opt.map(identity) == opt //Some(hello) == Some(hello)
//associative law
opt.map(f1 _ andThen f2) == opt.map(f1).map(f2) //Some(HELLOHELLO) == Some(HELLOHELLO)
opt.map(fNull _ andThen f2) == opt.map(fNull).map(f2) //Some(nullnull) == Some(nullnull)
But what if Option("hello").map(t=>null) produced None? Associative law would be broken:
opt.map(fNull _ andThen f2) == opt.map(fNull).map(f2) //Some(nullnull) != None
That is my thought, might be wrong