30

I'd like to do something like

def getMeASammy() {println "getMeASammy"}
def getMeADrink() {println "getMeADrink"}
def getMeASub() {println "getMeASub"}

But, I don't want to explicitly type out the name of the function.

Jija
  • 995
  • 8
  • 13
  • 1
    You can use stack traces, but not more on the subject should be mentioned in polite company... –  Jun 23 '10 at 20:04
  • I know nothing about Scala, but couldn't you use the Java reflection API for this? See e.g. [Does Scala have introspection capable of something similar to Python's dir()?](http://stackoverflow.com/questions/1973202/does-scala-have-introspection-capable-of-something-similar-to-pythons-dir) – ire_and_curses Jun 23 '10 at 20:18
  • 1
    When someone asks you your name, do you get out your wallet and check one of your IDs in order to answer? – Randall Schulz Jun 24 '10 at 00:23
  • 2
    @RandallSchulz Completely irrelevant. It is nice to have this sort of thing to make common test routines. – 2rs2ts Jul 08 '15 at 00:05

4 Answers4

50
scala> def currentMethodName() : String = Thread.currentThread.getStackTrace()(2).getMethodName
currentMethodName: ()String

scala> def getMeASammy() = { println(currentMethodName()) }
getMeASammy: ()Unit

scala> getMeASammy()
getMeASammy
Richard Fearn
  • 25,073
  • 7
  • 56
  • 55
  • 2
    I assume if you do getStackTrace()(3) you get the function calling it? – Zuoanqh Nov 30 '15 at 06:46
  • Will indices (2) or (3) ever fail? ex. should I do a null check? – Raymond26 Jul 29 '16 at 20:31
  • 1
    @Raymond26 No, I think it's pretty safe. Accessing element 2 means there must be at least three methods in the stack trace, which there will be - `getStackTrace`, the method calling `getStackTrace` (`currentMethodName` here), and the method calling that (`getMeASammy` here). Plus something must be calling `getMeASammy` for it to be executing (even if it's just the REPL, as shown here), so yes there will be a fourth item in the stack trace, and yes it's safe to use index 3. – Richard Fearn Jul 31 '16 at 16:27
5

It's somewhat revolting, but the only supported way to get the name of the current method from the JVM is to create an exception (but not throw it), and then read the method name out of the exception's stack trace.

def methodName:String= new Exception().getStackTrace().apply(1).getMethodName()
Krzysztof Atłasik
  • 21,985
  • 6
  • 54
  • 76
Dave Griffith
  • 20,435
  • 3
  • 55
  • 76
5

I wrote a simple library, which is using a macro to get the name of the function. It might be a more elegant solution than using Thread.currentThread.getStackTrace()(2).getMethodName if you don't mind additional dependency:

libraryDependencies += "com.github.katlasik" %% "functionmeta" % "0.2.3" % "provided"
import io.functionmeta._

def getMeASammy() {
   println(functionName) //will print "getMeASammy"
}
Krzysztof Atłasik
  • 21,985
  • 6
  • 54
  • 76
5

Nameof does exactly this, and at compile time, so there are no creating exceptions, inspecting the stack trace and other reflection-ish overhead.

Relevant example from nameof readme:

import com.github.dwickern.macros.NameOf._

  def startCalculation(value: Int): Unit = {
    println(s"Entered ${nameOf(startCalculation _)}")
  }

  // compiles to:

  def startCalculation(value: Int): Unit = {
    println(s"Entered startCalculation")
  }

In your case

def getMeASammy() = println(nameOf(getMeASammy _))

Also, nameOf works with classes, class attributes, types, etc.

J0HN
  • 26,063
  • 5
  • 54
  • 85