Search code examples
scalafileiofunctional-programmingtry-catch

Scala Try[String] found instead of String


I am trying to understand how Try works in scala (not try/catch) but Try. As an example, here I wish to check if the file exists, and if yes, I will use the data in the file later in the code, but it doesn't work:

val texte = Try(Source.fromFile(chemin_texte).getLines().filter(_!="").foldLeft(""){_+_})
        texte match {
          case Success(x) => x
          case Failure(e) => println("An error occured with the text file"); println("Error: " + e.getMessage)
        }

        /*phrases du texte*/
        val phrases_txt = split_phrases(texte).map(phrase => phrase)

At val phrases_txt I wish to use the output of texte if the file exists, if not the program should halt at Failure(e).

The error that I get is type mismatch; found: scala.util.Try[String] required: String .

Any help? Thanks.


Solution

  • Think of Try as just a container for a computation that can fail. It is not comparable with a try and catch block because they just "throw" the exceptions, which are expected to be handled later on in the program. Scala Try forces you to ensure that a possible error is handled at all times from that point onwards in your program.

    You can do something like this:

    val texte = Try(Source.fromFile(chemin_texte).getLines().filter(_!="").foldLeft(""){_+_})
    
    val phrases: Try[List[String]] = texte.map(split_phrases)
    

    I don't see the point of .map(phrases => phrases) because it will return the same object. The map function has a type of T[A] => T[B], so that means that for a container with values of type A, the map will run a given function f on the contents of the container and produce a container of type B where function f is responsible for converting an object of type A to type B.

    If you wish to further use your phrases object in your program with other values that produce Try values, you can use the flatMap function or for expressions that make life easier. For example:

    val morePhrases: Try[List[String]] = ???
    
    def mergePhrases(phrases1: List[String], phrases2: List[String]): Phrases = phrases1 ++ phrases2
    
    val mergedPhrases: Try[List[String]] = for {
      p1 <- phrases
      p2 <- morePhrases
    } yield mergePhrases(p1, p2) // Only for demonstration, you could also do yield p1 ++ p2
    

    The mergedPhrases value in the code above is just a Try container containing the result of application of mergePhrases function on contents of phrases and morePhrases.

    Note that the Try block may not always be the best way to capture error at the end of your program you'll what the first error occurred, but you won't know what exactly the error was. That's why we have things like Either.