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)
  @assert cur_expr.head == :function

  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 :grimacing:

1 Like

I’d also love to see @__FUNCTION__ added.