Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I would like to know the name of the current function from within that function. For example, consider the following code

myFunction[args___] :=
  Module[{},
    checkArgs[args,"myFunction"];
    someCode[]
  ];

where checkArgs is used in several functions which have the same types of arguments and reports an error message which includes the name of the function it was called from. I would like to call checkArgs without having to give it the name of the function.

The evaluation stack, obtained using Stack, I believe does not contain this information unless called from within a StackComplete, and this is generally not the case in normal use of the function.

I appreciate that "the current function" is not necessarily a well-defined concept in Mathematica, since you can have nested function definitions, and a function is just a rule definition anyway. However, the options management system uses this concept. If I have OptionsPattern in the function definition, I can call OptionValue[x], and something knows to look in Options[myFunction] to find the information about the options. So could whatever this mechanism is using be accessed? Is there a way to get the current function from the options system?

The best solution I have come up with is this:

(fn:myFunction)[args___] :=
  Module[{},
    checkArgs[args,fn];
    someCode[]
  ];

which avoids having to pass in the function name explicitly, but is still quite ugly.

share|improve this question
add comment

1 Answer 1

Custom assignement operators

Not quite what you asked for, but (as we already discussed recently), you can use custom assignment operators to define some variable that would have the value set to the name of your function inside its body. Here is a possibility:

ClearAll[def];
SetAttributes[def, HoldAll];
def /: SetDelayed[def[f_[args___]], rhs_] :=
   f[args] := Block[{$inFunction = f}, rhs];
Protect[def];

The above assignment operator is based on dynamic scoping. In case you want to bind lexically, you can do a similar thing, which in this case becomes a macro:

ClearAll[deflex];
SetAttributes[deflex, HoldAll];
deflex /: SetDelayed[deflex[f_[args___]], rhs_] :=
   Hold[rhs] /. HoldPattern[currentFunction] :> 
       f /. Hold[code_] :> SetDelayed @@ Hold[f[args], code];
Protect[deflex]

In contrast to def, the deflex operator does not wrap Block[{$inFunction = f}, ...] around the body of your function, but rather replaces all literal occurrences of currentFunction in the body of your function with f, before making a definition.

Example

The above form allows for a natural-looking code:

def @ myFunction[args___] :=
   Module[{}, checkArgs[args, $inFunction]]

so that you just have to add def @ to the usual definition. Here is the generated defintion:

?myFunction
Global`myFunction
myFunction[args___]:=
    Block[{$inFunction=myFunction},Module[{},checkArgs[args,$inFunction]]]

And here is a test:

myFunction[1,2,3]

(* checkArgs[1,2,3,myFunction] *)

You can do a similar thing with deflex:

ClearAll[mySecondFunction];
deflex @ mySecondFunction[args___] :=
   Module[{}, checkArgs[args, currentFunction]]

although the generated definition will be different:

?mySecondFunction
Global`mySecondFunction
mySecondFunction[args___]:=Module[{},checkArgs[args,mySecondFunction]]

In this case, both definitions efectively result in a similar run-time behavior, but there can be situations where this will not be the case.

Limitations

Note that this form of def (or deflex) can not handle definitions of this type:

def @ myFunction[args___] /; Length[{args}] > 1 :=
   Module[{}, checkArgs[args, $inFunction]]

but can handle a similar one like this:

def @ myFunction[args___] :=
   Module[{}, checkArgs[args, $inFunction]] /; Length[{args}] > 1
share|improve this answer
1  
A bit OT, but I always wondered: How does the magic behind OptionValue work? –  sebhofer Mar 4 '13 at 17:11
1  
@sebhofer The best I can tell at the moment is what is described in my answer to this question. –  Leonid Shifrin Mar 4 '13 at 17:25
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.