as a beginner in Scala - functional way, I'm little bit confused about whether should I put functions/methods for my case class inside such class (and then use things like method chaining, IDE hinting) or whether it is more functional approach to define functions outside the case class. Let's consider both approaches on very simple implementation of ring buffer:
1/ methods inside case class
case class RingBuffer[T](index: Int, data: Seq[T]) {
def shiftLeft: RingBuffer[T] = RingBuffer((index + 1) % data.size, data)
def shiftRight: RingBuffer[T] = RingBuffer((index + data.size - 1) % data.size, data)
def update(value: T) = RingBuffer(index, data.updated(index, value))
def head: T = data(index)
def length: Int = data.length
}
Using this approach, you can do stuff like methods chaining and IDE will be able to hint methods in such case:
val buffer = RingBuffer(0, Seq(1,2,3,4,5)) // 1,2,3,4,5
buffer.head // 1
val buffer2 = buffer.shiftLeft.shiftLeft // 3,4,5,1,2
buffer2.head // 3
2/ functions outside case class
case class RingBuffer[T](index: Int, data: Seq[T])
def shiftLeft[T](rb: RingBuffer[T]): RingBuffer[T] = RingBuffer((rb.index + 1) % rb.data.size, rb.data)
def shiftRight[T](rb: RingBuffer[T]): RingBuffer[T] = RingBuffer((rb.index + rb.data.size - 1) % rb.data.size, rb.data)
def update[T](value: T)(rb: RingBuffer[T]) = RingBuffer(rb.index, rb.data.updated(rb.index, value))
def head[T](rb: RingBuffer[T]): T = rb.data(rb.index)
def length[T](rb: RingBuffer[T]): Int = rb.data.length
This approach seems more functional to me, but I'm not sure how practical it is, because for example IDE won't be able to hint you all possible method calls as using methods chaining in previous example.
val buffer = RingBuffer(0, Seq(1,2,3,4,5)) // 1,2,3,4,5
head(buffer) // 1
val buffer2 = shiftLeft(shiftLeft(buffer)) // 3,4,5,1,2
head(buffer2) // 3
Using this approach, the pipe operator functionality can make the above 3rd line more readable:
implicit class Piped[A](private val a: A) extends AnyVal {
def |>[B](f: A => B) = f( a )
}
val buffer2 = buffer |> shiftLeft |> shiftLeft
Can you please summarize me your own view of advance/disadvance of particular approach and what's the common rule when to use which approach (if any)?
Thanks a lot.