Reputation: 255
For some special reasons, I want to remove the effect of all @tailrec in a big program, but don't want to do that manually, is there any optional arguments when compiling that can turn off the tail recursion optimization? I want to just leave the @tailrec in the code, but don't want to check it and do tail recursion optimization when compiling. Is that possible?
Upvotes: 2
Views: 698
Reputation: 51271
The @tailrec
annotation doesn't turn on/off tail recursion optimization. It only tells the compiler to error out if the annotated routine is not properly tail recursive.
If the routine is tail recursive then the optimization is there whether it's annotated or not.
From the docs:
A method annotation which verifies that the method will be compiled with tail call optimization.
If it is present, the compiler will issue an error if the method cannot be optimized into a loop.
The operative word being "verifies".
UPDATE
@mikołak is correct. A quick check shows that the -g:notailcalls
flag turns off annotation verification.
%%> scalac tailrec.scala
tailrec.scala:5: error: could not optimize @tailrec annotated method rf: it contains a recursive call not in tail position
def rf(x: Int): Int = if (x < 1) x else rf(x-2)+1
^
one error found
%%> scalac -g:notailcalls tailrec.scala
%%>
Upvotes: 3
Reputation: 9705
You can use the compiler's -g:notailcalls
option.
From the docs:
-g:{none,source,line,vars,notailcalls}
"none" generates no debugging info,
"source" generates only the source file attribute,
"line" generates source and line number information,
"vars" generates source, line number and local variable information,
"notailcalls" generates all of the above and will not perform tail call optimization.
Note, as the docs specify, that this will also enable debug info generation.
An example:
import scala.annotation.tailrec
class A {
@tailrec
final def x(i: Int): Int = if(i == 0) {i;} else {x(i-1)}
}
javap -p -v A.class
of x
when compiled "normally":
public final int x(int);
descriptor: (I)I
flags: ACC_PUBLIC, ACC_FINAL
Code:
stack=2, locals=2, args_size=2
0: iload_1
1: iconst_0
2: if_icmpne 7
5: iload_1
6: ireturn
7: iload_1
8: iconst_1
9: isub
10: istore_1
11: goto 0
The same, when compiled with -g:notailcalls
:
public final int x(int);
descriptor: (I)I
flags: ACC_PUBLIC, ACC_FINAL
Code:
stack=3, locals=2, args_size=2
0: iload_1
1: iconst_0
2: if_icmpne 9
5: iload_1
6: goto 16
9: aload_0
10: iload_1
11: iconst_1
12: isub
13: invokevirtual #12 // Method x:(I)I
16: ireturn
The important bit is the invokevirtual
on position 13
.
Note, by the way, that jwvh prudently corrected you on the interpetation of @tailrec
- it doesn't actually toggle tail optimization, the only thing that it does is that it informs the compiler to fail if it cannot insert a tail call optimization, which it would attempt anyway.
Upvotes: 6