Retrieve variable name inside function

Is it possible inside a function to retrieve the variable name of an argument to that function in form of a string?
Here my example function to investigate the nature of variables during the degugging phase:

function _DBG_type_and_size(_s_var_name::AbstractString, _value::Any, _is_DBG::Bool)
    if _is_DBG
        if ~isempty(size(_value))
            println(@sprintf("%-60s, type: ", _s_var_name), @sprintf("%20s", typeof(_value)), ",\t value: ", size(_value))
        elseif isreal(_value)
            println(@sprintf("%-60s, type: ", _s_var_name), @sprintf("%20s", typeof(_value)), ",\t value: ", @sprintf("%.3f", _value))
        else
            println(@sprintf("%-60s, type: ", _s_var_name), @sprintf("%20s", typeof(_value)), ",\t size: ",  _value)
        end
        flush(stdout)
    end
end

Now, I wonder if the first argument _s_var_name is a redundant information?

It is not.
That is only possible for a macro.
See e.g. Julia Language Tutorial => Reimplementing the @show macro

6 Likes

It is not redundant information. Say you define a method f(x) and you call f(y). The body of f(x) has no idea what y is, it had already assigned the associated instance to x for its local use. Instances generally are not reciprocally associated with any variable symbols. Notable exceptions where Symbol(instance) does work: modules, structs, functions (though only named ones would be recognizable).

You could make the call less redundant with a macro. Here’s a rough one: macro varval(var::Symbol) :($(Expr(:quote, var)), $var) end. You can write a call as somefunc(@varval(varname)..., other) to be parsed to somefunc( (:varname, varname)..., other). Doesn’t really save on typing though.

@oxinabox Thanks for this interesting link! :slight_smile:

I fugured out a method to reduce the number of arguments down to 2:

using Printf
function _DBG_investigate_variable(_s_var_name::AbstractString, _is_DBG::Bool)
    if _is_DBG
		_symbol_variable_name = Symbol(_s_var_name)
		@eval(_value = $_symbol_variable_name)
        if ~isempty(size(_value))
            println(@sprintf("%-60s, type: ", _s_var_name), @sprintf("%20s", typeof(_value)), ",\t size: ", size(_value))
        elseif isreal(_value)
            println(@sprintf("%-60s, type: ", _s_var_name), @sprintf("%20s", typeof(_value)), ",\t value: ", @sprintf("%.3f", _value))
        else
            println(@sprintf("%-60s, type: ", _s_var_name), @sprintf("%20s", typeof(_value)), ",\t value: ",  _value)
        end
        flush(stdout)
    end
end

But this works only, with simple situations, expressions like myvec[i] or yourvec[2] are only possible with the first variant.

The @eval there looks really fishy. What’s the point of it?

@kristoffer.carlsson The idea is, to reduce the number of inputs of my debugging helper from 3 to 2.
What do you propose?

P.S.:
I have also spent quite some time with the package Logging, but I have not figured out,
how to use it properly for degugging puposes, e.g. what I dislike is the amount of output it
generates, per each output.
P.P.S.:
The degugging inside visual studio is really frustrating, it is slow and it crashes frequently on my machine.

deleted

You might want to give GitHub - JuliaDebug/Infiltrator.jl: No-overhead breakpoints in Julia a go for debugging if the actual Debugger fails for your use case.

The reason why the @eval looks fishy is that eval operates in global scope, meaning that you can only use that function to debug global variables. The solution here is really to use a macro, something like

julia> macro _DBG_investigate_variable(var, enabled)
           name = string(var)
           return esc(:(_DBG_type_and_size($name, $var, $enabled)))
       end
@_DBG_investigate_variable (macro with 1 method)

julia> function f()
           bar = [1, 2]
           @_DBG_investigate_variable(bar[2], true)
       end
f (generic function with 1 method)

julia> f()
bar[2]                                                      , type:                Int64, value: 2.000
1 Like

@GunnarFarneback Thanks for the explanation, why @eval() is not the best idea! :slight_smile: