Way to treat function as symbol using boolean flag?

Let’s say you have a bunch of coefficients, i.e.

``````function K_PC(cur_blah::AbstractBlah)
cur_K = K_law(cur_blah)

cur_K *= K_G(cur_blah) ^ 2
cur_K *= 1.273

cur_K /= cur_blah.eta_T

cur_K
end
``````

However, you’re using `SymPy` and want to enable some sort of `symbolic mode`

// that doesn’t evaluate any of the values (i.e. leaves the output pretty)

Is there a way to know the name of `K_PC` inside itself?

This would allow you to short-circuit the function at the top with:

`return SymPy.symbols(<name_of_function>)`

// where `<name_of_function>` would be `K_PC` in this example

You could write a macro

``````@name function K_PC(cur_blah::AbstractBlah)
...
end
``````

That expands to something like

``````function K_PC(cur_blah::AbstractBlah)
__FUNCTION_NAME__ = :K_PC
...
end
``````
2 Likes

I think `string(stacktrace()[1].func)` will return the function’s own name (and `[2]` the function calling it, etc).

An alternative solution if you merely need it for DRY and want to avoid macros is to define your operations as types, then make them callable:

``````abstract type AbstractOp end

struct Op1 <: AbstractOp end

function (op::Op1)(arg)
Symbol(typeof(op))
end
``````

Also, you can define a

``````sympyname(::Op1) = :op1
``````

and thus decouple the two namespaces.

3 Likes

Pretty cool solutions across the board! Thanks for your help.

The code I ended up on is:

``````macro symbol_func(cur_expr::Expr)

cur_call = cur_expr.args[1]
cur_func_name = cur_call.args[1]
cur_main_var = cur_call.args[2].args[1]

cur_param = Expr(:kw, Expr(:(::), :is_direct_call, :Bool), false)

cur_sub_expr = parse("""
\$(cur_main_var).is_symbolic && !is_direct_call &&
return symbols("\$(cur_func_name)")
""")

push!(cur_expr.args[1].args, cur_param)
unshift!(cur_expr.args[2].args, cur_sub_expr)

cur_expr
end
``````

With the initial code now being:

``````@symbol_func function K_PC(cur_blah::AbstractBlah)
cur_K = K_law(cur_blah)

cur_K *= K_G(cur_blah) ^ 2
cur_K *= 1.273

cur_K /= cur_blah.eta_T

cur_K
end
``````

I was using this approach for a precondition marco that wants to use the function name in an error message. It turned out not to be generally reliable. Possibly because issue #19979 means that stack traces sometimes get corrupted when `try/catch` is used? Possibly due to inlining?

(Another variation of a precondition macro that needs the function name: https://github.com/JuliaLang/julia/pull/15495)

@srp asked for `@__FUNCTION__` a while back.

This issue should be re-opened because none of the referenced issues have implemented anything like `@__FUNCTION__`

https://github.com/JuliaLang/julia/issues/6733

2 Likes

Forgot to post a picture of the use case!

(left is a paper. right is code. and they match!)

update: already found 2 bugs in some code using this

1 Like

I’d also love to see `@__FUNCTION__` added.