First the background - I am writing some code to decode messages received from a socket. The nature of sockets means that these messages, received as ByteString
s may be complete, truncated or concatenated with other messages. The messages themselves are broken into a common header which contains the length of the variable data which follows.
My plan was to have functions that read the parts of the message, for example the first read could read the length of the variable data, the second the variable data itself.
When one of these methods is called, I want it to return the next operation which could be the next logical operation in the read sequence or itself if the particular read could not be performed because all the data required is yet to be received.
In the case that the data received from the socket is perfectly framed, the read operations would alternate between readLength
and readData
. However when data is read in multiple chunks from the socket it may be that the read operations follow a readLength
, readData
and readData
pattern.
Hope that made sense.
What I want to do is something like this (which won't compile because of the cyclic reference):
type ReadFunction = (ByteBuffer) => ReadFunction
So that I can declare something like this:
def readLength(buffer: ByteBuffer): ReadFunction = {
if (buffer.limit - buffer.position > 4) {
return readData(buffer.getInt)
}
else {
return readLength
}
}
def readData(length: Int)(buffer: ByteBuffer): ReadFunction = {
if (buffer.limit - buffer.position > length) {
val data: Array[Byte](size)
buffer.get(data)
//process data
readLength
}
else {
readData(length)
}
}
Now I know I can (and actually have) solve this by defining the read operations as classes that extend a common trait and return instances of each but that seems rather un-Scala like.
So my question is - how do you define a function that can return itself?
You can't use cyclic reference in type
declaration, but you can use it in class
or trait
declaration like this:
implicit class ReadFunction(f: Int => ReadFunction) extends (Int => ReadFunction) {
def apply(i: Int) = f(i)
}
lazy val read: ReadFunction = { i: Int => println(i); read }
scala> read(1)(2)(3)
1
2
3
res0: ReadFunction = <function1>
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments