4

I have been studying some posts on scala infinite streams to better wrap my head around this concept. I liked the simple solution in this post, which I have reproduced below:

def fib: Stream[Long] = {
  def tail(h: Long, n: Long): Stream[Long] = h #:: tail(n, h + n)
  tail(0, 1)
}

My initial understanding of what was going on was that we were returning a Stream[Long] object with the tail method overriden. To test out that (seemingly incorrect) hypothesis, I did the following, which would not compile:

def fib: Stream[Long] = {

  override def tail(h: Long, n: Long): Stream[Long] = h #:: tail(n, h + n)
     ^
     |
   ~error~~~

  tail(0, 1)
}

So this solution does seem to be based on an override. So, now I'm wondering.. what exactly is going on with Scala constructs that have a def of some type 'T' where the value of that block contains another def that, on first glance seems to override a method of T ?

Thanks in advance for enlightening me !

EDIT - here is the result of trying out the solution in the excellent answer from Mateusz Dymczyk :

object Foolaround  extends App {

  def fib: Stream[Long] = {
    def pail(h: Long, n: Long): Stream[Long] = h #:: pail(n, h + n)
    pail(0, 1)
  }

  var x = fib.tail.tail.tail.tail.tail.head
  println (s"results: ${x}")
}
Community
  • 1
  • 1
Chris Bedford
  • 2,560
  • 3
  • 28
  • 60

1 Answers1

6

To override a method X you would have to first create a class that extends some other class that contains a method X already. In your example you are actually not creating a new class anywhere! Here you just created a nested function inside another function which, unfortunately, is called tail (so has the same name as one of the functions inside the Stream).

So basically the fib method is returning a Stream instance which is recursively created by your nested tail function. To create the actual instance of the Stream that method is using the #:: operator.. You're not creating a new class, just a new instance.

The doc explains well what #:: is doing.

Try changing the name from tail to myTail (or any other name that's not part os the Stream) and you'll see it still works.

As for why would you use this construct: one common reason is to structure your code, you can notice that you cannot use that tail function outside it's outer method.

Mateusz Dymczyk
  • 14,969
  • 10
  • 59
  • 94
  • 1
    Ahh. got it. i tried renaming tail to pail.. but the trick is.. as you say.. the 'pail' function is not usable outside the definition of 'fib'. I should have realized this is a method within a method. Thanks for pointing that out. – Chris Bedford Aug 03 '15 at 02:15