How to fix Source is not closed warning

I’m trying to update some old code to Scala 3.2, and I get a warning (from intellij) on the following code.

  def parseFileByName(fileName: String): DimacsFile = {
    parseBufferedContent(Source.fromFile(fileName).buffered)
  }

The warning indicates that Source is not closed. What action should I take in this function to satisfy that warning?

By using Using (pun somewhat intended :sweat_smile:)

def parseFileByName(fileName: String): DimacsFile = {
  Using(Source.fromFile(fileName).buffered) { reader =>
    parseBufferedContent(reader)
  }
}

Does this change the semantics? These files can be huge. Does the suggested change load everything into memory at the same time?

It only makes sure the file is closed afterwards. No additional buffering.

1 Like

Looks like

  def parseFileByName(fileName: String): DimacsFile = {
    import scala.util.Using
    import scala.util.Try._
    Using(Source.fromFile(fileName).buffered) { reader =>
      parseBufferedContent(reader)
    } 
  }

returns not a DimacsFile but rather a Try[DimacsFile], and there’s a missing implicit.
Screenshot 2020-12-02 at 19.42.13

Am I supposed to get the DimacsFile using pattern matching?

  def parseFileByName(fileName: String): DimacsFile = {
    import scala.util._
    Using(Source.fromFile(fileName).buffered) { reader =>
      parseBufferedContent(reader)
    } match {
      case Success(f) => f
      case Failure(e) => throw e
    }
  }

Sorry, it should have been like this:

def parseFileByName(fileName: String): DimacsFile = {
  import scala.util.Using
  Using(Source.fromFile(fileName)) { source =>
    parseBufferedContent(source.buffered)
  } .get // This will throw if it was an error.
}

BTW, if the file is really big, you may consider using a Stream like fs2 or AkkaStreams.

As I understand, the .get obviates the need to pattern match Success vs Failure, but the problem of the missing implicit persists. Is this just a wrong warning from IntelliJ?

Looks like it is a real error. When I try to compile, I get the following error.

could not find implicit value for evidence parameter of type util.Using.Releasable[scala.collection.BufferedIterator[Char]]
    Using(Source.fromFile(fileName).buffered) { reader =>

There is no implicit for a BufferedIterator (it is not closable). Look at the code from BalmungSan.

1 Like

I see the problem!
I had

    Using(Source.fromFile(fileName).buffered) { reader =>
      parseBufferedContent(reader)
    }.get

rather than

    Using(Source.fromFile(fileName)) { reader =>
      parseBufferedContent(reader.buffered)
    }.get

In this case the compiler error was really misleading.

BTW, I’m always afraid to use the _ short hand for anonymous functions because I don’t understand how it decides what the function body is. How far out does it go?

    Using(Source.fromFile(fileName)) { parseBufferedContent(_.buffered) }.get

Is _.buffered the function
or is parseBufferedContent(_.buffered) the function
or is { parseBufferedContent(_.buffered) }.get
or is Using(Source.fromFile(fileName)) { parseBufferedContent(_.buffered) }
or is Using(Source.fromFile(fileName)) { parseBufferedContent(_.buffered) }.get

Some of those choices are of course ridiculous, but since I don’t know the rule, and I’ve been burned by it in the past, I tend to use

reader =>  parseBufferedContent(reader.buffered)

rather than

parseBufferedContent(_.buffered)
1 Like

In my experience, it doesn’t go beyond a pair of braces or parentheses, except for (_).

I wouldn’t be afraid, because if the expansion is not what you expected, the compiler will almost certainly complain. Because it has to infer the type of each underscore, it will only typecheck if used in a context where a function of known argument types is expected.

1 Like

If I’m not mistaken f(_,12) is a function, but f(_.get) calls f with a function as argument. Maybe I’m mistaken, but otherwise, that violates the idea that it stops at paren boundaries.

I personally also dislike the _ syntax.

It is not only about it being prone to error, is about making the code cleaner.

1 Like

It’s basically what @curoli said. It doesn’t go beyond the expression within a pair of parentheses except when it is the expression in the parentheses. _ is always a placeholder in a larger expression, it’s not an identity function.

Or Using.resource(...).

1 Like

Oh sweet! I need to remember that for future questions. I am already too used to cats but I usually try to (at least additionally) provide an std-only answer.