I am trying to solve a problem given by the Book "Scala for the Impatient", which asked to implement java's BufferedInputStream as a trait. Here is my implementation,
trait Buffering {
this:InputStream =>
private[this] val bis = {
new JavaBufferedInputStream(this)
}
override def read = bis.read
override def read(byte:Array[Byte], off:Int, len:Int) = bis.read(byte, off, len)
override def available = bis.available
override def close() {
bis.close
}
override def skip(n:Long) = bis.skip(n)
}
def main(args:Array[String]) {
val bfis = new FileInputStream(new File("foo.txt")) with Buffering
println(bfis.read)
bfis.close
}
But this give me a java stackoverflow error, so what's wrong with it? Thanks!
It looks like you are getting a stack overflow where you don't expect one. The key to troubleshoot these is to look at the repeating cycle of the stack trace. It usually points to what is repeatedly allocating frames. Here it will show something like that:
at C.Buffering$class.read(C.scala:12)
at C.C$$anon$1.read(C.scala:23)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
at C.Buffering$class.read(C.scala:12)
at C.C$$anon$1.read(C.scala:23)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
at C.Buffering$class.read(C.scala:12)
So reading from bottom to top, it looks like your read(byte, ...)
is calling bis.read(byte, ...)
which is calling BufferedInputStream.read
which is then calling your read(byte, ...)
again.
It would appear that new BufferedInputStream(this)
is calling read
on the underlying InputStream
but since the underlying this
is your object that then delegates calls on bis
we have infinite recursion.
I'm guessing that the author wants you to use the abstract override
stackable modifications pattern where you can use super
to refer to the right read
method.
Maybe this is the answer. Just maybe from what i understood.
trait Buffering extends InputStream{
abstract override def read()=
{
println("Hello");
super.read()
}
}
val t = new ByteArrayInputStream("hello".getBytes()) with Buffering
I have been going through "Scala for the Impatient". Here is what I have as a solution to exercise 8 in chapter 10:
import java.io._
object BufferedInputStream extends App {
trait Buffering {
this: FileInputStream =>
val br = new BufferedInputStream(this)
}
def bufferedReader(f: String): Unit = {
val fis = new FileInputStream(f) with Buffering
var c = 0
var blen = 8192
var len = 0
var b = new Array[Byte](blen)
while (fis.br.available > 0) {
if (fis.br.available > blen) len = blen
else len = fis.br.available
c = fis.br.read(b, 0, len)
if (c == -1) return
print((for (i <- 0 to (c - 1)) yield b(i).toChar).mkString)
}
fis.br.close
fis.close
}
bufferedReader("webpagexample")
}