7

It is possible to get current line number by __LINE__ in Ruby or Perl. For example:

print "filename: #{__FILE__}, line: #{__LINE__}"

Is there the same feature in Groovy?

kwatch
  • 508
  • 1
  • 5
  • 12

2 Answers2

3

Not directly, but you can get it through an Exception (or Throwable) stack trace. For example:

 StackTraceElement getStackFrame(String debugMethodName) {
     def ignorePackages = [
         'sun.',
         'java.lang',
         'org.codehaus',
         'groovy.lang'
     ]
     StackTraceElement frame = null
     Throwable t = new Throwable()
     t.stackTrace.eachWithIndex { StackTraceElement stElement, int index ->
         if (stElement.methodName.contains(debugMethodName)) {
             int callerIndex = index + 1
             while (t.stackTrace[callerIndex].isNativeMethod() ||
                    ignorePackages.any { String packageName ->
                        t.stackTrace[callerIndex].className.startsWith(packageName)
                    }) {
                 callerIndex++
             }
             frame = t.stackTrace[callerIndex]
             return
         }
     }
     frame
 }

 int getLineNumber() {
     getStackFrame('getLineNumber')?.lineNumber ?: -1
 }

 String getFileName() {
     getStackFrame('getFileName')?.fileName
 }

 String getMethodName() {
     getStackFrame('getMethodName')?.methodName
 }

 def foo() {
     println "looking at $fileName:$lineNumber ($methodName)"
 }

 foo()

 // ==> looking at test.groovy:39 (foo)

A word of caution though: getting the line number, file name, or method like this is very slow.

ataylor
  • 64,891
  • 24
  • 161
  • 189
  • Why is it so slow? The equivalent in Perl (meaning, via `caller`) is very fast. – tchrist Feb 23 '12 at 18:51
  • Java stack traces can be quite deep, groovy even more so. The method [Throwable.fillInStackTrace](http://docs.oracle.com/javase/6/docs/api/java/lang/Throwable.html#fillInStackTrace%28%29) just takes a while to build the stack trace data structure. Check out http://stackoverflow.com/a/3980148/190201 for a more in depth look. It's certainly not too slow to use for debugging, but it's good to be aware of its cost before using it. – ataylor Feb 23 '12 at 19:10
1

I'm not an expert in Groovy, but I don't think so. I know that Java and C# don't have it.

The __LINE__ feature really started to help with debugging in C. C doesn't have exceptions or many of the other features modern languages have, but it did have macros that the compiler could expand anywhere in the code, which is why we needed __FILE__, __LINE__, etc to let us know where we were when something bad happened. This is how assert works in C and C++. The JVM has very good debugging tools, and combined with assert and exceptions, you can very easily pinpoint where something went wrong (stack traces are way better than just a line number anyway).

I believe the reason Ruby and Perl have those macros is because they were created by C hackers. I've never used either of those languages enough to know the level of debugging support or how useful the macros really are.

parkovski
  • 1,503
  • 10
  • 13
  • I can confirm that they aren’t really used much. The normal way to get info about a frame in Perl, whether inside the debugger or outside of it, is to use the `caller` function with a frame number as the argument. 0 is where you are right now, 1 is your caller, 2 is *his* caller, etc. This now returns that frame’s package, filename, line, subroutine, and a bunch of other things. So you would normally use the functional interface to get that info, not the old `__FILE__` and `__LINE__` pseudo-macros. – tchrist Feb 23 '12 at 05:30