Search code examples
scalafor-looprandomaccessfilefor-comprehension

for-comprehension, guard and RandomAccessFile.readLine


Consider the following:

There is a textfile with a certain amount of lines, like:

test.txt: a b c d e f g h

(each in there own line)

Then there is the following class used for parsing:

class MyAwesomeParser
{
    def parse(fileName: String, readLines: Int): IndexedSeq[String] =
    {
        val randomAccessFile = new RandomAccessFile(fileName, "r")

        val x: IndexedSeq[String] = for
        {
            x <- 0 until readLines
            r = randomAccessFile.readLine()
        } yield r

        x
    }
}

Here come the tests:

class MyAwesomeParserTest extends WordSpec
{
    "MyAwesomeParser" when {
    "read" should {
      "parse only specified number of lines" in {
        val parser = new EdgeParser("")
        val x = parser.parse("test.txt", 5)

        assert(x.size == 5)
      }
    }

    "MyAwesomeParser" when {
    "read" should {
      "parse only until end of file" in {
        val parser = new EdgeParser("")
        val x = parser.parse("test.txt", 10)

        assert(x.size == 8)
      }
    }
  }
}

Second test is the problematic one. Now of course you say, you're missing a guard here... well, well, if I add

x <- 0 until readLines if randomAccessFile.readLine != null

to the implementation then it skips a few lines, because readLine already consumes the line.

  r = randomAccessFile.readLine
  x <- 0 until readLines if r != null

will not work sadly, as first one line has to be assignment for comprehension.

Now I wonder, is it even possible with a for comprehension to loop until a given amount of times OR stop before based on that readLine != null condition?

Is my syntax just broken?


Solution

  • You may encapsulate randomAccessFile.readLine in an Option, so that null will be changed to None and value to Some(value).

    Moreover, Option can be considered as a collection, so you may put it in the same for comprehension as the IndexedSeq:

    for {
      x <- 0 until readLines
      r <- Option(randomAccessFile.readLine())
    } yield r