Code runs with fastOptJS but fails with fullOptJS in Scala.js - scala.js

I'm catching an UndefinedBehaviorError thrown by the bad asInstanceOf in my code like this:
$("button").on(
"click",
".showDialog",
(event: JQueryEventObject) => {
event.preventDefault()
val helpText = "Enter any number"
js.Dynamic.global.swal(
JC(
title = helpText,
text = helpText,
`type` = "input",
showCancelButton = true,
closeOnConfirm = false,
inputPlaceholder = helpText
),
(input: Any) => {
try {
input.asInstanceOf[Boolean]
} catch {
case _: Throwable =>
try {
val correctInput = input.asInstanceOf[String].toDouble
global.console.log("success")
} catch {
case _: Throwable =>
js.Dynamic.global.swal.showInputError("Incorrect data!")
}
}
}
)
}
)
It works fine with fastOptJS but fails with fullOptJS. How to correctly rewrite this code to run it with fullOptJS or what are the other options?

In Scala.js, a bad cast does not reliably throw a ClassCastException, unlike in Scala/JVM. Instead, a bad cast is an undefined behavior, as specified here. This means that in fullOpt, the program can behave arbitrarily, and in particular is allowed not in throw. In fastOpt, however, the compiler is kind and reliably throws, but not a ClassCastException (as it would give a false sense of security), rather an UndefinedBehaviorError.
UndefinedBehaviorErrors must never be caught, as catching one hides a bug which will surface in fullOpt. This is your mistake here: you are catching that UndefinedBehaviorError under case _: Throwable =>. Note that catching Throwable is bad practice in Scala. Instead, you should be using case scala.util.control.NonFatal(_) =>. A NonFatal handler does not catch UndefinedBehaviorError, and would therefore not hide the bug.
Now to solve your issue, you simply not use asInstanceOf as a means to type-test. Even on Scala/JVM, that code would be super bad practice. Use pattern matching instead:
(input: Any) => {
def reportIncorrectData(): Unit =
js.Dynamic.global.swal.showInputError("Incorrect data!")
input match {
case input: Boolean =>
// Here, input is a Boolean
input
case input: String =>
// Here, it is a String; let's try to convert it to Double
try {
val correctInput = input.toDouble
} catch {
case _: NumberFormatException =>
reportIncorrectData()
}
case _ =>
// It is something else, always incorrect data
reportIncorrectData()
}
}

Related

Scala "Try" return type and exception handling

I am a newbie for Scala and now am trying to complete an exercise. How can I return an InvalidCartException while the function return type is Try[Price]
//Success: return the calculated price
//Failure: InvalidCartException
def calculateCartPrice(cart:Cart): Try[Price] = {
if(isCartValid(cart)) {
//Calculations happen here
return Try(Price(totalPrice));
}
}
def isCartValid(cart: Cart): Boolean = {
//THIS WORKS FINE
}
Thank you for the help
If you mean "how to make the Try contain an exception", then use the Failure() like below:
def calculateCartPrice(cart:Cart): Try[Price] = {
if(isCartValid(cart)) {
//Calculations happen here
Success(Price(totalPrice));
} else {
Failure(new InvalidCartException())
}
}
Then, given a Try you can use getOrElse to get the value of success or throw the exception.
Try will catch the exception for you, so put the code that can throw the exception in there. For example
def divideOneBy(x: Int): Try[Int] = Try { 1 / x}
divideOneBy(0) // Failure(java.lang.ArithmeticException: / by zero)
If what you have is a Try and you want to throw the exception when you have a Failure, then you can use pattern matching to do that:
val result = divideByOne(0)
result match {
case Failure(exception) => throw exception
case Success(_) => // What happens here?
}
The Neophyte's Guide to Scala has lots of useful information for people new to Scala (I found it invaluable when I was learning).

How to avoid 'Non-variable type argument is unchecked since it is eliminated by erasure'?

A project I am working on has the following piece code:
val ftr1: Future[Try[(Date, String)]] = Future {
if (someCondition) {
// some code
val amazonClient = Try[new com.amazonaws.services.s3.AmazonS3Client(...)]
amazonClient.map { c =>
// doing some stuff
(new Date, "SomeString")
}
} else {
// some code
Failure(new Exception)
}
}
Future.firstCompletedOf(Seq(ftr1, anotherFuture)) map {
case t: Try[(Date, String)] => {
t match {
case Success(r) => //do some things
case _ => //do some another things
}
case _ => //do some another things
}
So, during compiling I have following warning:
[warn] non-variable type argument java.util.Date in type pattern java.util.Date, String) is unchecked since it is eliminated by erasure
and
[warn] case t: (Date, String) => //do some things
And I actually do not understand, what these warnings mean and how can this code be refactored in order to get rid of these warnings?
Try[+T] is an abstract class, one which you can't create an instance of.
There are two case classes which inherit from it, Success and Failure, which you should really be using.
The compiler is warning you that at compile time, type erasure is going to erase those types, thus matching on them isn't going to get you the results you want. More on that can be found in How do I get around type erasure on Scala? Or, why can't I get the type parameter of my collections?
But, you can avoid all this completely if you simply match on Success and Failure to reduce the unnecessary nesting in your match:
val ftr1: Future[Try[(Date, String)]] = Future {
if (someCondition) {
// some code
val amazonClient = Try { /* stuff */ }
amazonClient.map { c =>
// doing some stuff
(new Date, "SomeString")
} else Failure(new Exception)
}
Future.firstCompletedOf(Seq(ftr1, anotherFuture)) map {
case Success((date, myString)) => /* do stuff */
case Failure(e) => log(e)
}

Scala: *.map(*) running in a Future, how to abort map?

#volatile var breakRequested: Boolean = false
// ...
def futureFunc(): Option[Iterable[String]] = {
val result = hugeList.map { item =>
if(breakRequested) {
// put exit code here
// return None
// throw AnException
// what else?
}
item.toText() // time-expensive function
}
Some(result)
}
Future { futureFunc() }
Given somebody set the breakRequested flag to true: How may I exit the map?
What I tried:
return None => such a return transformed into a scala.runtime.NonLocalReturnControl: I tried to catch this error, but it seems to be uncatchable (bypasses try/catch).
object Cancelled extends Exception: I tried to throw this but was not able to catch it as well.
All exceptions show up in the command line, when I run the app through SBT.
If somehow possible, I prefer a solution without try/catch.
For the fast solution, you can convert your hugeList to the Iterator, and then use takeWhile:
...
val result = hugeList.toIterator
.takeWhile(_ => !breakRequested)
.map { item =>
item.text
}
...
Edit:
Scala's Future has no cancellation, but twitter's Future has. To cancel this use method raise.
Also you can write your own map, for example:
#annotation.tailrec def map[T,R](
src: List[T],
cancel: => Boolean,
dsc: List[R] = List.empty[R])(f: T => R):List[R] = src match {
case _ if cancel => dsc
case h :: t => map(t, cancel, f(h) :: dsc)(f)
case Nil => dsc
}
Future{map(hugeList, breakRequested)(_.text)}
If you don't need the result, you can create another future,which will be completed after your breakRequested was changed. And use method Future.firstCompletedOf.

What is the proper way to return from an exception in Scala?

In a non-functional language, I might do something like:
try {
// some stuff
} catch Exception ex {
return false;
}
// Do more stuff
return true;
In Scala, however, this pattern is clearly not correct. If my scala code looks like this:
try {
// do some stuff
}
catch {
case e: Exception => // I want to get out of here and return false
)
}
// do more stuff
true
How do I properly do that? I don't want to use the "return" statement, of course, but I also don't want to drop through and "do more stuff" and eventually return true.
You want to represent a computation that can either succeed or signal that an error has occurred. That's the perfect use case for the Try monad.
import scala.util.{ Try, Success, Failure }
def myMethod: Try[Something] = Try {
// do stuff
// do more stuff
// if any exception occurs here, it gets wrapped into a Failure(e)
}
So you're returning a Try instead of a Bool, which is infinitely more clear and idiomatic.
Usage example:
myMethod match {
case Success(x) => println(s"computation succeded with result $x")
case Failure(e) => println(s"computation failed with exception $e.getMessage")
}
If you don't even care about the exception, but you just want to return a value in case of success, you can even convert the Try to an Option.
def myMethod: Option[Something] = Try {
// do stuff
// do more stuff
// return something
// if any exception occurs here, it gets wrapped into a Failure(e)
}.toOption
myMethod match {
case Some(x) => println(s"computation succeded with result $x")
case None => println("computation failed")
}
To respond to the question in the comments, you can do
Try {
// do stuff
} match {
case Failure(_) => false
case Success(_) =>
// do more stuff
// true
}
although I would suggest to return something more meaningful than a Boolean, whenever it makes sense.
Of course this can be nested
Try {
// do stuff
} match {
case Failure(_) => false
case Success(_) =>
// do more stuff
Try {
// something that can throw
} match {
case Failure(_) => false
case Success(_) =>
// do more stuff
true
}
}
but you should consider putting the Try chunks into separate functions (returning a Try).
Ultimately, we can take advantage of the fact that Try is a monad, and do something like this
Try { /* java code */ }.flatMap { _ =>
// do more stuff
Try { /* java code */ }.flatMap { _ =>
// do more stuff
Try { /* java code */ }
}
} match {
case Failure(_) => false // in case any of the Try blocks has thrown an Exception
case Success(_) => true // everything went smooth
}
scala> def f() = try { ??? ; 1 } catch { case _: Throwable => 2 }
f: ()Int
scala> f()
res2: Int = 2
scala> import util._
import util._
scala> def g() = Try { ??? ; 1 } recover { case _ => 2 } get
warning: there was one feature warning; re-run with -feature for details
g: ()Int
scala> g()
res3: Int = 2
HTH. Small functions helps.
Another hint:
scala> def j() = Try (1) map (_ + 42) recover { case _ => 2 } get
warning: there was one feature warning; re-run with -feature for details
j: ()Int
scala> j()
res4: Int = 43
try-catch expression is not good for functional programming.
Anyway, an easy solution that still uses try-catch:
val result = try {
// do some stuff
Some(/* The final expression */)
}
catch {
case e: Exception => // Do something or nothing
None
}
result match {
case Some(r) => // Do something with r
true
case None => false
}
You can use scala.util.Try for cleaner and more functional-styled code.
Refer to https://codereview.stackexchange.com/questions/38689/code-with-many-early-returns-exits-into-the-functional-style
I faced a similar problem like you, but the answer in the Stackexchange CodeReview helped me a lot.
Successful or erroneous cases can be represented by several Scala type.
If you consider the error in the meaning of "something is missing" (e.g. file not found), you can use Option[T] (e.g. Option[File]), with case values None or Some(T). Then orElse, getOrElse or fold and map/flatMap functions can be used to dispatch cased.
You can also use Either[E, T], with (by convention), in Left(E) case the error value (e.g. a String as error message), and in Right(T) successful T value.
Monads Try[T] or Future[T] can be used in the same way.
In the field of I/O, the very nice scala-arm lib provide type ManagedResource[T] that wrap either successful (T) or erroneous (List[Throwable]]) result of computation based on resources.
Valudation types in Scalaz are also useful for such cases.
'util.Try{ do some stuff }.isSuccess'

How do I write this without using a Try/Catch block?

I am looking to rewrite this scala function, but I am new to the language, I understand there is a alternative to using try\catch blocks. How would you guys rewrite this function?
def updateStationPost = Action { implicit request =>
StationForm.bindFromRequest.fold(
errors => { //needs to be revised!!
BadRequest(html.updateStation(errors,
Station(
request.body.asFormUrlEncoded.get("id")(0).toLong,
request.body.asFormUrlEncoded.get("operator")(0).toLong,
request.body.asFormUrlEncoded.get("name")(0),
try {
request.body.asFormUrlEncoded.get("number")(0).toInt
} catch {
case e:Exception => { 0 } //this exception happens when trying to convert the number when there is nothing in the flash scope to convert.
},
request.body.asFormUrlEncoded.get("timezone")(0)
),
Operators.retrieveJustOperators() //ugh... needs to be revised..
)
)
},
{ case(stationFormObj) =>
Stations.update(stationFormObj)
Redirect(routes.StationsController.index)
}
)
}
A general way of managing this is to use Try to wrap code that could throw an exception. Some of the ways of using this are illustrated below:
def unpredictable() = {
Try(Console.readLine("Int please: ").toInt) getOrElse 0
}
If the console read does not contain a parseable integer, then it throws an exception. This code just returns a 0 if there was an error, but you could put other statements there. As an alternative, you could use pattern matching to handle the situation.
def unpredictable() = {
Try(Console.readLine("Int please: ").toInt) match {
case Success(i) => i
case Failure(e) => println(e.getMessage())
}
}
You can also just return a Try and let the caller decide how to handle the failure.
How about:
import scala.util.control.Exception.handling
// Create a val like this as you reuse it over and over
val form: Option[Map[String, Seq[String]]] = request.body.asFormUrlEncoded
// Create some helper functions like this
val nfeHandler = handling(classOf[NumberFormatException]) by (_ => 0)
val intNFEHandler = (str: String) => nfeHandler apply str.toInt
val longNFEHandler = (str: String) => nfeHandler apply str.toLong
// You can use this instead of your try catch.. but this is just a sugar.. perhaps cleaner
intNFEHandler apply form.get("id")(0)
Here if the form was something like: Option(Map("id" -> Seq.empty[String]))
form.get("id")(0) would blow up with java.lang.IndexOutOfBoundsException.
I would suggest to have another helper:
// takes fieldNames and returns Option(fieldValue)
val fieldValueOpt = (fieldName: String) => form.flatMap(_.get(fieldName).flatMap(_.headOption))
Then create a validate method which performs pattern matching on all the fieldValue optionals, extract the values and create your Station object.