@tailrec annotation

147 views
Skip to first unread message

Mohammad Almalkawi

unread,
Sep 22, 2012, 1:32:08 AM9/22/12
to scala-c...@googlegroups.com
I came across this very useful annotation: @tailrec

It triggers a compiler error if a recursive method is not tail recursive.

* Example where a compile error will be generated:
@tailrec
def sum(xs: List[Int]): Int = {
  if (xs.isEmpty)
    0
  else
    xs.head + sum(xs.tail)
}

* Example where compiling will succeed after changing sum to tail recursion:
def sum(xs: List[Int]): Int = {
  @tailrec
  def sum(xs: List[Int], accumulator: Int): Int = {
    if (xs.isEmpty)
      accumulator
    else
      sum(xs.tail, xs.head + accumulator)
  }

  sum(xs, 0)
}


For more details about tail recursion:

Pankaj Gupta

unread,
Sep 22, 2012, 4:55:57 AM9/22/12
to scala-c...@googlegroups.com
Hurray, all assignments done and submitted. All tests were passing, still got only 9.98 out of 10. Wondering where I lost my 2 cents.

--
You received this message because you are subscribed to the Google Groups "Scala discussion based on Coursera" group.
To unsubscribe from this group, send email to scala-courser...@googlegroups.com.
Visit this group at http://groups.google.com/group/scala-coursera?hl=en.
 
 

Pankaj Gupta

unread,
Sep 22, 2012, 4:59:55 AM9/22/12
to scala-c...@googlegroups.com
Yes, this annotation is super critical for ensuring good performance I've heard. Haven't used it so far as most of the functional scala programming I have done so far has been with toy programs. Looking forward to using FP more.

On Sep 21, 2012, at 10:32 PM, Mohammad Almalkawi wrote:

Sharmin Choksey

unread,
Sep 22, 2012, 5:10:31 PM9/22/12
to scala-c...@googlegroups.com
Very nicely explained in the post.

Pankaj,

try sbt styleCheck, if that does not return warnings, then see what the submission feedback has to say.  I fixed a redundant "if" statement based on the autograder feedback to get a full score.

Robert Kohlenberger

unread,
Sep 25, 2012, 1:02:40 AM9/25/12
to scala-c...@googlegroups.com
Pankaj,

Good work!

Using styleCheck found a cyclomatic complexity problem which I fixed, but autograder gave me only 9.58, some problem with Pascal's Triangle, but the feedback doesn't give me a clue.  At first I thought it was a timeout issue, since one of my tests uses large rows and columns (pascal(16, 33)) but I resubmitted with that commented that out and still get 9.58.  Here's the autograder feedback.

======== LOG OF FAILED TESTS ========

Your solution achieved a testing score of 180 out of 190.
Below you can see a short feedback for every test that failed, indicating the reason
for the test failure and how many points you lost for each individual test.

[Test Description] pascal: base cases
[Observed Error] org.scalatest.exceptions.TestFailedException: 0 did not equal 1
  [exception was thrown] detailed error message in debug output section below
[Lost Points] 10

======== DEBUG OUTPUT OF TESTING TOOL ========

[test failure log] test name: pascal: base cases
java.util.concurrent.ExecutionException: org.scalatest.exceptions.TestFailedException: 0 did not equal 1
java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:262)
java.util.concurrent.FutureTask.get(FutureTask.java:119)
grading.GradingSuite$class.timeoutTask(GradingSuite.scala:30)
recfun.PascalSuite.timeoutTask(PascalSuite.scala:10)
grading.GradingSuite$class.runWithoutPrivileges(GradingSuite.scala:69)
recfun.PascalSuite.runWithoutPrivileges(PascalSuite.scala:10)
grading.GradingSuite$$anonfun$test$1.apply$mcV$sp(GradingSuite.scala:78)
grading.GradingSuite$$anonfun$test$1.apply(GradingSuite.scala:78)
grading.GradingSuite$$anonfun$test$1.apply(GradingSuite.scala:78)
org.scalatest.FunSuite$$anon$1.apply(FunSuite.scala:1265)
org.scalatest.Suite$class.withFixture(Suite.scala:1974)
recfun.PascalSuite.withFixture(PascalSuite.scala:10)
org.scalatest.FunSuite$class.invokeWithFixture$1(FunSuite.scala:1262)
org.scalatest.FunSuite$$anonfun$runTest$1.apply(FunSuite.scala:1271)
org.scalatest.FunSuite$$anonfun$runTest$1.apply(FunSuite.scala:1271)
org.scalatest.SuperEngine.runTestImpl(Engine.scala:198)
org.scalatest.FunSuite$class.runTest(FunSuite.scala:1271)
recfun.PascalSuite.runTest(PascalSuite.scala:10)
org.scalatest.FunSuite$$anonfun$runTests$1.apply(FunSuite.scala:1304)
org.scalatest.FunSuite$$anonfun$runTests$1.apply(FunSuite.scala:1304)
org.scalatest.SuperEngine$$anonfun$org$scalatest$SuperEngine$$runTestsInBranch$1.apply(Engine.scala:260)
org.scalatest.SuperEngine$$anonfun$org$scalatest$SuperEngine$$runTestsInBranch$1.apply(Engine.scala:249)
scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
scala.collection.immutable.List.foreach(List.scala:76) org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:249)
All I get out of this is that some test in the Grading Suite expected 0 but got 1 (or vice versa).  Any ideas?

Thanks,
Bob

Robert Kohlenberger

unread,
Sep 25, 2012, 1:47:05 AM9/25/12
to scala-c...@googlegroups.com
Found the problem!  All points outside Pascal's Triangle must be 1, but I was returning 0.  This was not clear to me from the exercise description, but I guess it makes sense.  Resubmitting the new code on a hunch yielded full score. - Bob

Pankaj Gupta

unread,
Sep 25, 2012, 2:03:46 AM9/25/12
to scala-c...@googlegroups.com
Nice. Mine turned out to be the same issue as Sharmin, a redundant if. Study group is helping already.
Reply all
Reply to author
Forward
0 new messages