Convert String to function name


#1

It is reasonably trivial to create a dataframe of function calls and then use the table to conditionally execute those functions. My question is, can the dataframe be stored to a file and then recovered?

When stored to a file, the function names are automatically converted to Strings. So the question is, how to convert a String to a function name such that it might be called. (i.e. result = df[1,:A](params) works where :A is a column of function names but does not work when reading the dataframe from a file)


#2

http://docs.julialang.org/en/stable/manual/metaprogramming/#symbols

Symbol("string")

#3

Symbol() will convert the string “a” to a Symbol :a but not a predefined function #a. Symbols, like strings, are not callable.


#4

A symbol is callable (that’s how functions are represented by the parser in an expression), you have to wrap the function call in an @eval:

julia> a = Symbol("sin")
:sin

julia> @eval $a(0.5)
0.479425538604203

#5

Thank you - this is very helpfull!


#6

You do not need (and should not use, if you can help it) eval for this, as far as I understand:


julia> s = Symbol("sin")
:sin

julia> f = getfield(Main, s)
sin (generic function with 10 methods)

julia> f(3)
0.1411200080598672

julia> sin(3)
0.1411200080598672

You can use current_module() if the symbol is in a different module.

By the way, I don’t think that a DataFrame is necessary here?


#8

Oh, that’s interesting, thank you! I didn’t know this use of getfield, as it’s documented nowhere in the manual (nor it’s obvious from the docstring of getfield, I’ve always use it only to extract fields from composite objects).

Turning a string into a function is something often needed in metaprogramming, it’s worth mentioning this in the manual.


#9

I agree. Would you like to try making a Pull Request to add this?


#10

I’d be really happy to do that… if I knew this argument better :wink: I think that among us, you’re the one who knows the details of this trick.


#11

This did the trick perfectly - thanks dpsanders.

A side note; the eval solution mentioned above does not work when the code is loaded with include(). It does not make it through the compile process.

Although the DataFrame is not a prerequisite, if this is being documented, I’d suggest a note in the readtable and writetable sections as the conversion from funtion name to string required to store the table drove the need for the conversation.


#12

I’ve done a fair amount of metaprogramming, and I don’t recall ever needing this. Can you elaborate?

Metaprogramming in Julia rarely requires manipulating code in the form of strings, and even more rarely requires eval or similar, because Julia provides you with much more powerful metaprogramming facilities (macros and generated functions that directly access the syntax tree).


#13

I can’t provide an experience in Julia (which I don’t have in this regard), but I code in Emacs Lisp and find that intern is used a lot to programmatically define and access functions and variables. How do you concatenate symbols to build up a new symbol name that doesn’t exist? (If this is possible, please share, it’s entirely possible that I just don’t know how to do it without strings and @eval ;-)). Probably what I described is rarely needed in Julia because of what it’s generally used for, and in this I may agree with you.


#14

gensym. Same as in emacs-lisp, actually. (EDIT: if the point is to get a symbol that does not clash with anything.)


#15

No, the intent would be to define new functions and variables that don’t exist, not for hygiene purposes.

Since you use AUCTeX, in that package string interning is used a lot by the TeX parser. it’s used to automatically define functions and variables (with attached docstrings) specialized for generic “stuff”. This “stuff” can be LaTeX macros, environments, counters. Again, probably in Julia you wouldn’t need to do that at all because you can have a generic method for an abstract type and then define concrete subtypes of it. This example was just to show that string interning can be used for something not related to hygiene.


#16
julia> a = :z
:z

julia> [Symbol(a, i) for i in 1:5]
5-element Array{Symbol,1}:
 :z1
 :z2
 :z3
 :z4
 :z5

#17

[quote=“dpsanders, post:16, topic:1547, full:true”]

julia> [Symbol(a, i) for i in 1:5]

```[/quote]
...which under the hood converts symbols to strings and concatenates strings ;-)

Now that you have the `:z1` symbol, how do you define the variable `z1` without using `@eval`?  For sure you can't use `getfield` here (unless there are other undocumented tricks).

#18

…which under the hood is a series of 0s and 1s. Point is that if you work with syntax you should probably work with Exprs and Symbols and not strings (nor 0s and 1s).

If the symbol :z1 is only known at run-time and you want to create a variable of that name then you need to use eval indeed. However, in those cases it is often better to use a dict. But using eval is fine, there are plenty of times it is used in base, e.g. here.


#19

Symbol("foo", "bar") or Symbol(:foo, 3) work, for example. However, in this kind of code generation you rarely if ever need to look up the value (binding) of the resulting symbol — that was what confused me.


#20

My point was that it isn’t a heresy to say that this kind of symbols manipulation can be done through manipulation of strings, that’s indeed what Symbol does :wink:

Anyway, one important lesson of this thread is that in most cases it isn’t necessary to play with strings.

Indeed I had already seen many times using symbols + @eval to programmatically define methods for functions in the standard library, that’s why I was surprised to read that @eval isn’t usually necessary. But I think the question is now settled for everyone.

Returning to the original argument of the thread, my understanding is that getfield is instructed (in src/builtins.c) to treat Module as if it were a composite type made up of all symbols it bears (either functions or variables), that’s why it’s possible to call a function or a variable, even not exported, with Module.symbol_name, like what you do to access fields of composite types.

Actually, Module type is not defined in that way, instead its fields are

help?> Module
search: Module module module_name module_parent baremodule current_module

  No documentation found.

  Summary:

  type Module <: Any

  Fields:

  name   :: Symbol
  parent :: Any

but the above description is a useful way to see Module type and understand how it works.

Is this correct? I couldn’t find this description in the manual (maybe because it’s wrong? :smiley: I skimmed through http://docs.julialang.org/en/latest/manual/metaprogramming.html and http://docs.julialang.org/en/latest/manual/modules.html) and, if it’s true and it isn’t indeed there, I think it could be a useful addition.


#21

Taking strings, and using @eval to turn those into function definitions in a loop, was something I learned early on from your very nice package https://github.com/stevengj/DecFP.jl (which looks like it needs updating for v0.5 and v0.6).
Would that sort of use be an acceptable exception then, or is there some better way of handling that now that I’ve missed?