0

My use-case is more complicated but basically below is the simplified example of what I am trying to achieve (my original code is for akka-stream):

offset := 0

//pump data
def pump(): Unit = {
    elem := poller.getNumberFromOffset(offset)

    elem match {
        case null => doSomething()
        case Completed => doSomethingElse()
        case _ => 
            offset += 1
            //check if the element is matched with a pre-supplied selector/filter function
            if(filterFunc(elem)) {
                doSomething2()
            } else {
                //if the element doesn't match; increase offset and try again; can sleep for a while here               
                pump()
            }
    }
}

The problem is that pump() function might result in stack-overflow (because pump function is called over-and-over again for a specific condition).

I can write the function into a non-recursive version like the following:

offset := 0

//pump data
def pump(): Unit = {
    elem := poller.getNumberFromOffset(offset)
    while(elem != null && elem != Completed && !filterFunc(elem)) {
        offset += 1
        elem = poller.getNumberFromOffset(offset)
    }       

    elem match {
        case null => doSomething()
        case Completed => doSomethingElse()
        case _ =>           
            offset += 1
            doSomething2()
    }
}

However my use-case is much more complicated; so I would really like to use the recursion function if it's possible instead of converting the existing code to while/for loop.

My question is "should I do so" and is there any difference if I just simply put @tailrec annotation on the first example so that scala complier will treat pump as tail-recursion function (@tailrec def pump(): Unit = {}). In my case, the pump() function should be called separatedly / after fixed interval; so stack-frame is really not necessary here.

Thanks.

2
  • 4
    "is there any difference if I just simply put @tailrec annotation on the first example" – No. The @tailrec annotation makes no difference. Tail-recursive methods are always optimized. (More precisely: methods that satisfy the conditions laid out in the spec.) The only thing the @tailrec annotation does is generate a compiler error if the method is not tail-recursive. It does not change whether or not the method gets optimized. Commented Feb 1, 2017 at 10:58
  • I challenge your pattern matching on null. Instead, I would wrap your possible null value in Option#apply. Example: Option[String] { null } === None Commented Feb 1, 2017 at 14:25

1 Answer 1

1

If you put @tailrec and the compiler lets you run it, this implies your piece of code is eligible for tail recursion optimization. Internally scala compiler will convert the tail recursive code to a loop. I dont think a tail recursive function will cause a stackoverflow error.So your pump() function wont cause stackoverflow if it satisfies @tailrec.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.