groovy git commit: Documentation for @TailRecursive (closes #808)

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

groovy git commit: Documentation for @TailRecursive (closes #808)

paulk
Repository: groovy
Updated Branches:
  refs/heads/GROOVY_2_5_X 6a91e9dbe -> 42e1d824b


Documentation for @TailRecursive (closes #808)


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/42e1d824
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/42e1d824
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/42e1d824

Branch: refs/heads/GROOVY_2_5_X
Commit: 42e1d824b3f4354003d53516559973369eff7fa8
Parents: 6a91e9d
Author: Jacob Aae Mikkelsen <[hidden email]>
Authored: Tue Oct 9 14:07:16 2018 +0200
Committer: Paul King <[hidden email]>
Committed: Thu Oct 11 13:13:38 2018 +1000

----------------------------------------------------------------------
 src/spec/doc/core-metaprogramming.adoc          | 16 +++++++++++-
 .../test/ClassDesignASTTransformsTest.groovy    | 27 ++++++++++++++++++++
 2 files changed, 42 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/42e1d824/src/spec/doc/core-metaprogramming.adoc
----------------------------------------------------------------------
diff --git a/src/spec/doc/core-metaprogramming.adoc b/src/spec/doc/core-metaprogramming.adoc
index dc165d9..4e47196 100644
--- a/src/spec/doc/core-metaprogramming.adoc
+++ b/src/spec/doc/core-metaprogramming.adoc
@@ -1985,7 +1985,21 @@ _protectedCacheSize>0_ would create an unlimited cache with some results protect
 [[xform-TailRecursive]]
 ===== `@groovy.transform.TailRecursive`
 
-TBD
+The `@TailRecursive` annotation can be used to automatically transform a recursive call at the end of a method
+into an equivalent iterative version of the same code. This avoids stack overflow due to too many recursive calls.
+Below is an example of use when calculating factorial:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassDesignASTTransformsTest.groovy[tags=tailrecursive,indent=0]
+----
+
+Currently, the annotation will only work for self-recursive method calls, i.e. a single recursive call to the exact same method again.
+Consider using Closures and `trampoline()` if you have a scenario involving simple mutual recursion.
+Also note that only non-void methods are currently handled (void calls will result in a compilation error).
+
+CAUTION: Currently, some forms of method overloading can trick the compiler,
+and some non-tail recursive calls are erroneously treated as tail recursive.
 
 [[xform-Singleton]]
 ===== `@groovy.lang.Singleton`

http://git-wip-us.apache.org/repos/asf/groovy/blob/42e1d824/src/spec/test/ClassDesignASTTransformsTest.groovy
----------------------------------------------------------------------
diff --git a/src/spec/test/ClassDesignASTTransformsTest.groovy b/src/spec/test/ClassDesignASTTransformsTest.groovy
index 09e829f..cd32da4 100644
--- a/src/spec/test/ClassDesignASTTransformsTest.groovy
+++ b/src/spec/test/ClassDesignASTTransformsTest.groovy
@@ -448,4 +448,31 @@ assert GreetingService.instance.greeting('Bob') == 'Hello, Bob!'
 // end::singleton_example_lazy[]
 '''
     }
+
+    void testTailRecursive() {
+        assertScript '''
+// tag::tailrecursive[]
+import groovy.transform.CompileStatic
+import groovy.transform.TailRecursive
+
+@CompileStatic
+class Factorial {
+
+    @TailRecursive
+    static BigInteger factorial( BigInteger i, BigInteger product = 1) {
+        if( i == 1) {
+            return product
+        }
+        return factorial(i-1, product*i)
+    }
+}
+
+assert Factorial.factorial(1) == 1
+assert Factorial.factorial(3) == 6
+assert Factorial.factorial(5) == 120
+assert Factorial.factorial(50000).toString().size() == 213237 // Big number and no Stack Overflow
+// end::tailrecursive[]
+'''
+    }
+
 }