Determine current function name

672 views
Skip to first unread message

Dominique Orban

unread,
Aug 5, 2015, 12:05:00 PM8/5/15
to julia-users
Sorry if this has been asked before. Is it possible to determine the name of a function inside that function? For example,

function blah(x)
  my_name
= ...  # should evaluate to "blah" or :blah
end

I didn't see that in the introspection section of the documentation.

Thanks!

Isaiah Norton

unread,
Aug 5, 2015, 12:36:22 PM8/5/15
to julia...@googlegroups.com
No.

Ok, technically, you could do this (inspired by https://github.com/JuliaLang/julia/issues/8066#issuecomment-61136584):

julia> function foo()
       bt = backtrace()
       lookup = ccall(:jl_lookup_code_address, Any, (Ptr{Void}, Int32), bt[2], 0)
       name = lookup[1]
       end
foo (generic function with 1 method)

julia> foo()
:foo

But that is a really, really bad idea. Please don't do that.

Isaiah Norton

unread,
Aug 5, 2015, 12:48:31 PM8/5/15
to julia...@googlegroups.com
Can I ask what is your use-case, and whether you've done this in some other language? From a quick google there are appear to be some (possibly non-standard) C and C++ compiler defines that provide the current function name, but other than that:

- Python rejected a PEP for this feature (https://www.python.org/dev/peps/pep-3130/)
- Java does not support it in a first-class way ("could use stacktrace, but potentially unreliable")
- some lisps appear to have interactive mode support for this kind of introspection, but nothing general.

The recommended way to solve problems that require this level of introspection is to do code generation via metaprogramming.

Tim Holy

unread,
Aug 5, 2015, 12:54:38 PM8/5/15
to julia...@googlegroups.com
Alternatively,

julia> for (offset, f) in enumerate((:foo1, :foo2, :foo3))
@eval begin
function $f(x)
println("This is ", $f)
x + $offset
end
end
end

julia> foo1(0)
This is foo1
1

julia> foo2(0)
This is foo2
2

julia> foo3(0)
This is foo3
3

--Tim

Cedric St-Jean

unread,
Aug 5, 2015, 2:10:53 PM8/5/15
to julia-users
I also wish that the name was visible... I wrote the macro a few days ago:

macro expose_name(fdef)
   
@capture(fdef, begin function fname_ (args__) body__ end end)
    esc
(:(function $(fname) ($(args...))
        let function_name
= $(Expr(:quote, fname))
           $
(body...)
   
end))
end

@expose_name function foo () @show function_name end

Cédric

Isaiah Norton

unread,
Aug 5, 2015, 2:25:42 PM8/5/15
to julia...@googlegroups.com
I'm still curious what problem / design this is trying to solve. Be aware that doing something like this for custom runtime dispatching is likely to be slow (except in the macro case which does not really count).

Are you both coming from some other programming language that exposes this in a first-class way? Both PHP and JavaScript seem to make this information available, but R does not (except for a callstack hack).

Cedric St-Jean

unread,
Aug 5, 2015, 2:42:26 PM8/5/15
to julia-users
In my case, I wanted to count how many times some functions were called. Kinda like a profiler, but for a different purpose. If the function name was available, I could move the macro "call" inside the function body, which would make more sense.

Yichao Yu

unread,
Aug 5, 2015, 3:56:12 PM8/5/15
to Julia Users
On Wed, Aug 5, 2015 at 2:42 PM, Cedric St-Jean <cedric...@gmail.com> wrote:
> In my case, I wanted to count how many times some functions were called.
> Kinda like a profiler, but for a different purpose. If the function name was
> available, I could move the macro "call" inside the function body, which
> would make more sense.

Than what about sth like

```julia
macro count_execute()
@gensym counter
quote
global $counter
if isdefined(:($counter))
$counter = $counter::Int + 1
else
$counter = 0
end
end
end
```

Dominique Orban

unread,
Aug 5, 2015, 4:39:23 PM8/5/15
to julia-users
My use case is that I'm writing a large number of functions, all displaying messages containing the function name (think informative error messages). Accessing the function name would slightly simplify the code.

The Python PEP was rejected but it's still possible in Python (e.g., using the introspect module). It's even possible in Matlab (using dbstack)! (I'm not saying it's entirely safe.)

Cedric St-Jean

unread,
Aug 5, 2015, 9:47:31 PM8/5/15
to julia-users
Yichao Yu: How would you retrieve the counter's value? How would you distinguish between the counter in function foo vs. the one in function bar?


On Wednesday, August 5, 2015 at 3:56:12 PM UTC-4, Yichao Yu wrote:

Tim Holy

unread,
Aug 5, 2015, 10:59:18 PM8/5/15
to julia...@googlegroups.com
You may want to check the IProfile.jl package, which does a lot of this kind of
stuff (including inserting timing code around each line of a function).

--Tim

Yichao Yu

unread,
Aug 5, 2015, 11:45:49 PM8/5/15
to Julia Users
On Wed, Aug 5, 2015 at 9:47 PM, Cedric St-Jean <cedric...@gmail.com> wrote:
> Yichao Yu: How would you retrieve the counter's value? How would you
> distinguish between the counter in function foo vs. the one in function bar?

I'm not sure what do you need the function name for. The code I post
(which has some issue about quoting for `isdefined` btw) is mainly for
having a unique counter for each function in case that's the only
thing you need the function name for. Also note that the function name
is not a good way to garentee uniqueness since it can have multiple
methods and specializations etc.

Cedric St-Jean

unread,
Aug 6, 2015, 10:36:10 AM8/6/15
to julia-users
On Wednesday, August 5, 2015 at 10:59:18 PM UTC-4, Tim Holy wrote:
You may want to check the IProfile.jl package, which does a lot of this kind of
stuff (including inserting timing code around each line of a function).

That was an interesting read, thank you. As a common lisper, all those gensyms were oddly comforting.

Cédric
 

David Gold

unread,
Aug 6, 2015, 11:58:31 AM8/6/15
to julia-users
For counting, is there a reason why you can't use a `let` block?

let count = 0
    global foo
    function foo(args...)
        count += 1
        ...
    end

    global foo_count()
    function foo_count()
        return count
    end
end # let count
Reply all
Reply to author
Forward
0 new messages