title: scala functional - methods/functions inside or outside case class?
body: <p>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 <em>functional</em> approach to define functions outside the case class. Let's consider both approaches on very simple implementation of <em>ring buffer</em>:</p>
  
  <p><strong>1/ methods inside case class</strong></p>
  
  <pre><code>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
  }
  </code></pre>
  
  <p>Using this approach, you can do stuff like methods chaining and IDE will be able to hint methods in such case:</p>
  
  <pre><code>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
  </code></pre>
  
  <p><strong>2/ functions outside case class</strong></p>
  
  <pre><code>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
  </code></pre>
  
  <p>This approach seems <em>more functional</em> 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.</p>
  
  <pre><code>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
  </code></pre>
  
  <p>Using this approach, the <em>pipe operator</em> functionality can make the above 3rd line more readable:</p>
  
  <pre><code>implicit class Piped[A](private val a: A) extends AnyVal {
    def |&gt;[B](f: A =&gt; B) = f( a )
  }
  
  val buffer2 = buffer |&gt; shiftLeft |&gt; shiftLeft
  </code></pre>
  
  <hr>
  
  <p>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)?</p>
  
  <p>Thanks a lot.</p>