In my opinion there are two things to consider. First, you want to evaluate the right hand side of your MyAddToCounter
during installing your program to ensure that $CurrentLink
has a value. Second, it is good practive to give your function a usage
message. Although, this is not required here since you have no Private`
context and the package context is prepended to the $ContextPath
when EndPackage
is called. This leaves you with
int AddToCounter P(( int));
:Evaluate: BeginPackage[ "counter`"]
:Begin:
:Function: AddToCounter
:Pattern: AddToCounter[$CurrentLink, n_Integer]
:Arguments: {n}
:ArgumentTypes: {Integer}
:ReturnType: Integer
:End:
:Evaluate: AddToCounter::usage = "AddToCounter[ ck, n] adds n to the counter ..."
:Evaluate: MyAddToCounter::usage = "Pure energy."
:Evaluate: MyAddToCounter[link_, n_Integer] := AddToCounter[link,n+1]
:Evaluate: EndPackage[ ]
and everything should work fine. Let me make clear what really happens here:
The pattern for AddToCounter
contains the symbol $CurrentLink
which gets a different value everytime you Install
your program. Therefore, when you have n different installations of your MathLink program, you have n different rules in the DownValues
of AddToCounter
.
On the other hand MyAddToCounter
does always have the same pattern and therefore no additional down value rule is added when you install a new instance. Depending on how clever Mathematica is the line MyAddToCounter[link_, n_Integer] := AddToCounter[link,n+1]
(with an arbitrary complex rhs) is processed every time you install a new instance without any use.
For such occasions I would suggest that you don't pack the code inside the template file. It is completely sufficient to evaluate
BeginPackage["counter`"];
MyAddToCounter[link_, n_Integer] := AddToCounter[link, n];
EndPackage[];
one time inside your Mathematica session or inside a package which is loaded.
If you do have a function which requires to make use of the $CurrentLink
you cannot simply make a definition like f[..]:=...$CurrentLink...
. Remember that SetDelayed
(:=
) does not evaluate its right side. Therefore, $CurrentLink
is not evaluate and stays in the definition as symbol. One possible solution is for instance a construct like this
With[{link = $CurrentLink},
MyAddToCounter[link, n_Integer] := AddToCounter[link, n];
]
inside the template code.
The conclusion is: If you have an additional function which does not explicitly depend on $CurrentLink
but only gives it through to a real template-function, you can simply define it inside Mathematica. If it depends explicitly on $CurrentLink
you need to put in in the template code and you need to ensure that it is evaluated correctly during the installation process.
Compilation of the sample code
Anyone interested can try this fast by copying counter.tm
from the examples directory and adapting the paths in the code below. If you are on Windows you may have to use mprep.exe
in the Run
call
tmfile = "/home/patrick/Documents/notebooks/SE/counter.tm";
{cfile, outfile} = StringReplace[tmfile, start__ ~~ ".tm" :> start ~~ #] & /@ {".c", ""};
Run[$InstallationDirectory <>
"/SystemFiles/Links/MathLink/DeveloperKit/"<> $SystemID <>
"/CompilerAdditions/mprep", tmfile, "-o", cfile]
<< CCompilerDriver`
prog = CreateExecutable[{cfile}, "counter", "ShellOutputFunction" :> Print,
"ShellCommandFunction" :> Print]
lnk = Install[prog]
MyAddToCounter[lnk, 20]
MyAddToCounter[link_,n_Integer] := AddToCounter[link,n+1]
, or simplyMyAddToCounter[n_Integer] := AddToCounter[$CurrentLink,n+1]
. The$CurrentLink
variable is a global variable and you don't have to include it in the function's signature. It is likely different when you call the function that when you define it, and so the pattern does not match. $\endgroup$Install
defines$CurrentLink
and inserts it whereever specified. However, in cases ofSetDelayed
the function is not evaluated until an explicit call to the function. But at that point the$CurrentLink
is not valid anymore. Hence we need ordinary variable passing! Thanks a lot! That helped! $\endgroup$Install
and scoping. Usually I just look at the source code generated bymprep
when I have questions, but had no time today. In any case, one should not answer in comments, and you give a full-fledged answer with explanations, so your answer is the answer here. I am actually very happy that you did it since I am quite busy at the moment. I think SE model is pushing us to think too often about the timing and to race to be the first at all costs. I dislike this, we should collaborate more. $\endgroup$Private`
subsection in the package, usage message is not necessary to export the symbol (I also initially thought it is), as the symbol is already created in the package main context. Of course, having a usage message is a good style anyway. $\endgroup$