user4564280
user4564280

Reputation:

catch a string in boolean option

How do I prevent error when someone does not choose one of the options in scala. This is using Map to get options and I tried to implement Try and catch blocks in case options but it does not work. I'm not sure if this is the right way to do it, if there is any other way let me know. The error is Exception in thread "main" java.lang.NumberFormatException: For input string: "e".

object main extends menu {
  def main(args: Array[String]): Unit = {
    var opt = 0
    do { opt = readOption }
    while (menu(opt))
  }
}   

class menu extends database {
  def menu(option: Int): Boolean = try {
    actionMap.get(option) match {
      case Some(a) => a()
      case None => println("That didn't work.")
      false
    }
  } catch {
  case _: NumberFormatException => true
  }
  val actionMap = Map[Int, () => Boolean](1 -> cWords, 2 -> cCharacters, 3 -> exit)

def readOption: Int = {
    println(
      """|Please select one of the following:
         |  1 - Count Words
         |  2 - Count Characters in words
         |  3 - quit""".stripMargin)
    StdIn.readInt()
}

Upvotes: 2

Views: 720

Answers (3)

elm
elm

Reputation: 20415

Use scala.util.Try on readInt(),

import scala.io._
import scala.util._

Try(StdIn.readInt()).toOption
// returns Some(123) for input 123

Try(StdIn.readInt()).toOption
// returns None for input 1a3

Thus readOption delivers Option[Int]. Then

def menu(option: Option[Int]): Boolean = option match {
  case Some(a) => actionMap(a)()
  case None    => println("Try again..."); false
}

Note

A more concise version of main,

def main(args: Array[String]): Unit = while (menu(readOption)) ()

Namely, while menu is true do Unit (or () ).

Upvotes: 1

pedrorijo91
pedrorijo91

Reputation: 7845

I would make readOption return a Try[Int], (a Try surrounding StdIn.readInt()), then deal with the possible cases in the menu function

Upvotes: 0

Łukasz
Łukasz

Reputation: 8663

Here is some working implementation:

import scala.io.StdIn
import scala.util.Try

object Main extends Menu with App {
    while (menu(readChoice)) ()
}

class Menu {
  val actionMap = Map[Int, () => Boolean](1 -> (() => true), 2 -> (() => true), 3 -> (() => false))

  def menu(choice: Option[Int]): Boolean = {
    choice.flatMap(actionMap.get)
      .map(action => action())
      .getOrElse({ println("That didn't work."); false })
  }

  def readChoice: Option[Int] = {
    println(
      """|Please select one of the following:
         |  1 - Count Words
         |  2 - Count Characters in words
         |  3 - quit""".stripMargin)
    Try(StdIn.readInt).toOption
  }
}

For the first, you can mixin App trait to skip main method boilerplate.

You can simplify your do while loop like this, it has to do nothing inside so you either need some expression or block. A Unit value can be your expression that does nothing.

In scala we name classes using camel case, starting with capital letter.

As readInt throws whenever input is wrong you can catch that using Try, that will return Success(result) of Failure(exception) and change this result to an Option to discard the exception.

what happens in menu is shorthand for

choice match {
  case Some(number) =>
    actionMap.get(number) match {
      case Some(action) =>
        action()
      case None =>
        println("That didn't work.")
        false
    }
  case None =>
    println("That didn't work.")
    false
}

And could be as well written with for

(for {
  number <- choice
  action <- actionMap.get(number)
} yield {
  action()
}) getOrElse {
  println("That didn't work.")
  false
}

On as sidenote, you named choice of user an "option" which unfortunately is also a scala class used here extensively, I renamed the variables to avoid confusion.

Upvotes: 0

Related Questions