Casting error from Option[Double] to Double in scala - scala

I am facing a problem in casting from Option[Double] to Double. I am getting the following exception error:
scala.Some cannot be cast to java.lang.Double
val ty = ttnew.distinct().leftOuterJoin(rank).map{ case ((key),(c,d)) => (key,c._1,c._2,c._3,d.getOrElse(Double).asInstanceOf[Double]) }
Please Help!

d.getOrElse(Double).asInstanceOf[Double]
makes no sense.
Assuming d is an Option[Double] if you want to have a Double you cannot cast it, you need to get the value "out of" the Option.
getOrElse allows you to get the value if present, and provide a fallback value if absent (i.e. None).
For example:
d.getOrElse(0) // 0, or anything that makes sense as a fallback
If d has type Option[Double] then d.getOrElse(0) has type Double.

that's not how you deal with Option. Use .getOrElse or a .map
val ty=ttnew.distinct().leftOuterJoin(rank).map{ case ((key),(c,d)) => (key,c._1,c._2,c._3,d.getOrElse(Double).asInstanceOf[Double]) }
probably (in this situation) you will want to do d.getOrElse(<a-good-default-value-like-zero-maybe>)
other situations maybe you want to propagate the meaning of Option (the value may not exist), and in those cases you should use the .map:
val res: Option[String] = optionalDouble.map(doubleValue => callSomeFunctionThatConvertsDoubleToString(value))
you can even do other things using pattern matching and extractors. for instance, using .collect (it's a .map, but there may be cases not covered):
val ty=ttnew.distinct().leftOuterJoin(rank).collect{ case ((key),(c,Some(d))) => (key,c._1,c._2,c._3,d) }

Related

scala mutable.Map put/get handles null's in an unexpected way?

I know one is not supposed to use nulls in scala but sometimes when interoperating with Java it happens. The way a scala mutable map handles this seems off though:
scala> import scala.collection.mutable
import scala.collection.mutable
scala> val m: mutable.Map[String, String] = mutable.Map.empty
m: scala.collection.mutable.Map[String,String] = Map()
scala> m.put("Bogus", null)
res0: Option[String] = None
scala> m.get("Bogus")
res1: Option[String] = Some(null)
scala> m.getOrElse("Bogus", "default")
res2: String = null
I would have expected m.get to return None in this case. Almost seems like a bug, like somewhere in the code there was a Some(v) instead of Option(v)
Is there discussion w/r/t to changing this behavior?
I would have expected m.get to return None in this case.
Why? None would mean the key "Bogus" is not in the map, but you just put it in (with value null).
Java's Map API has problems distinguishing "the value for this key is null" from "this key is not in the map", but Scala's doesn't.
Null is subtype of String:
scala> implicitly[Null <:< String]
res3: Null <:< String = <function1>
Therefore null is a valid String value:
scala> val s: String = null
s: String = null
If you want to store a null as a String in a map, it's your good right.
Compared to Java's Map#get (let's call it javaLikeGet), the Scala's get behaves roughly as follows:
def get(k: K) = if (containsKey(k)) {
Some(this.javaLikeGet(k))
} else {
None
}
and not like what you have assumed:
def get(k: K) = Option(this.javaLikeGet(k))
The latter version (presumably what you thought) would get a null for an existing key, pass it to Option(...), and return None. But the former version (which imitates how the real implementation works) would notice that the key exists, and wrap the null returned by javaLikeGet into a Some.
The simple and consistent rule is:
If the key k exists, then get(k) returns Some[V], otherwise it returns None.
This is much less surprising than the strange behavior of Java's get that returns null in two entirely different situations.
This is the Billion-Dollar Mistake, but Scala is not the language that is likely to fix it, because it has to interop with Java. My guess is that there is and will be no discussion about changing this behavior, at least not until something fundamentally changes in the entire programming landscape.

Scala Syntactic Sugar for converting to `Option`

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).

Why does Scalaz \/ type have getOrElse but not get?

As far as I can tell Scalaz's \/ does not have get method. Sometimes I am sure the value contained in \/ is the right value, and I don't want to use getOrElse. I want to get it directly.
("3".right[Int]) getOrElse("123123123") // 3
if (t.isRight) t.get // compilation error, no get method
How can I get the right value directly, if it is guaranteed.
There are two ways I can get the value, but both look a little bit verbose.
1: change to scala Either
val t = "3".right[Int]
val either = t.toEither
if (either.isRight) either.right.get
else either.left.get
2: Use getOrElse
("3".right[Int]) getOrElse("123123123") // but for some cases I don't have this default value
There is no get as get could throw an exception, which isn't cool. Scalaz enforces this by not allowing direct access to the value.
If you provide more information, we can help out with a solution.
t should be safe.
val safe_thing:T = ???
val either: Throwable \/ T = getFromSomewhere
either getOrElse safe_thing
As other answer pointed out, get could throw. But similarly to OP, I also encountered cases when I was sure of a type (in this case \/-), yet the variable in code was of type \/ (super class).
Doing inline pattern matching was very verbose and looked bad.
println(("test".right[String] |> { case \/-(x) => x; case _ => "" }).toUpperCase)
So I wrote this helper:
implicit class ScalazDisjunctionPimps[A, B](e: \/[A, B]) {
def getRight: B = e match {
case \/-(x) => x
case _ => throw new RuntimeException(s"$e is not right.")
}
}
Usage is simple, here's example:
println("test".right.getRight.toUpperCase) // outputs: TEST
If needed getLeft can be constructed in the same way.

avoid type conversion in Scala

I have this weird requirement where data comes in as name ->value pair from a service and all the name-> value type is string only (which really they are not but that's how data is stored)
This is a simplified illustration.
case class EntityObject(type:String,value:String)
EntityObject("boolean","true")
now when getting that EntityObject if type is "boolean" then I have to make sure value is not anything else but boolean so first get type out and check value and cast value to that type. e.g in this case check value is boolean so have to cast string value to boolean to validate. If it was anything else besides boolean then it should fail.
e.g. if data came in as below, casting will fail and it should report back to the caller about this error.
EntityObject("boolean","1")
Due to this weird requirement it forces type conversion in validation code which doesn't look elegant and against type safe programming. Any elegant way to handle this in scala (may be in a more type safe manner)?
Here is where I'm going to channel an idea taken from a tweet by Miles Sabin in regards to hereogenous mappings (see this gist on github.) If you know the type of object mapping names a head of time you can use a nifty little trick which involves dependent types. Hold on, 'cause it's a wild ride:
trait AssocConv[K] { type V ; def convert: String => V }
def makeConv[V0](name: String, con: String => V0) = new AssocConv[name.type]{
V = V0
val convert = con
}
implicit val boolConv = makeConv("boolean", yourMappingFunc)
def convEntity(name: String, value: String)(implicit conv: AssocConv[name.type]): Try[conv.V] = Try{ conv.convert(value) }
I haven't tested this but it "should" work. I've also enclosed it in a Scala Try so that it catches exceptions thrown by your conversion function (in case you're doing things like _.toInt as the converter.)
You're really talking about conversion, not casting. Casting would be if the value really were an instance of Boolean at runtime, whereas what you have is a String representation of a Boolean.
If you're already working with a case class, I think a pattern matching expression would work pretty well here.
For example,
def convert(entity : EntityObject) : Any = entity match {
case EntityObject("boolean", "true") => true
case EntityObject("boolean", "false") => false
case EntityObject("string", s) => s
// TODO: add Regex-based matchers for numeric types
}
Anything that doesn't match one of the specified patterns would cause a MatchError, or you could put a catchall expression at the end to throw your own exception.
In this particular example, since the function returns Any, the calling coffee would need to do an actual type cast to get the specific type, but at least by that point all validation/conversion would have already been performed. Alternatively, you could just put the code that uses the values directly into the above function and avoid casting. I don't know what your specific needs are, so I can't offer anything more detailed.

scala.Some cannot be cast to java.lang.String

In this application, I'm getting this error:
scala.Some cannot be cast to java.lang.String
When trying this:
x.email.asInstanceOf[String]
x.email is an Option[String]
Edit: I understand that I'm dealing with different types here, I was just wondering if there were a more concise way to do nothing with None then a
match { case....}
sequence. Because I am casting x.email into a String for JSON purposes, a null field will be handled by the JSON object, and I don't explicitly have to deal with it. Sorry for being unclear!!
Well, it's clear to you from the errors and types that x.email is not a String...
First, decide how you want to handle None (a valid option for something of type Option[String]). You then have a number of options, including but not limited to:
x.email match {
case None => ...
case Some(value) => println(value) // value is of type String
}
Alternately, take a look at the get and getOrElse methods on class Option.
If you want to "degrade" the option to a String with a possible null value, then use
x.email.orNull // calls getOrElse(null)
Finally, if you just don't care about the None case (and want to ignore it), then just use a simple "for comprehension" which will "skip" the body in the None case:
for (value <- x.email) {
// value is of type String
}
Casting isn't how you should be looking at conversions when it comes to Options. Have a look at the following REPL session:
C:\>scala -deprecation -unchecked
Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0).
Type in expressions to have them evaluated. Type :help for more information.
scala> val email:Option[String] = Some("x#y.com")
email: Option[String] = Some(x#y.com)
scala> email.getOrElse("defaults#example.com")
res0: String = x#y.com
scala>
You might also want to look at this SO question: What is the point of the class Option[T]?
and the Options API here
Generally speaking, casting/coercion are kind-of taboo in FP world. :)
x.map(_.toString).getOrElse("")
You may want use pattern matching:
x.email match {
case Some(email) => // do something with email
case None => // did not get the email, deal with it
}