# How hide symbolic definition of a function?

How can the actual definition of a function be hidden from a user?

I want the user of a notebook to be able to evaluate a real-valued function f of a real variable at any particular numeric input yet not be able to see the symbolic expression that defines it. E.g.:

f[x_]:=Exp[-x] Cos[2x]


Of course I know I want to hide the definition of f in a package, say func.m consisting of something like the following:

BeginPackage["func"]
f::usage = "f[x] gives the value of the secret function f at x";

Begin["Private"]
f[x_]:=Exp[-x] Cos[2x]
End[]

EndPackage[]


This package file would be Encoded and put into the same directory as a notebook, say work.nb where the user will work with the hidden definition. And this notebook would include, in an Initialization cell:

SetDirectory[NotebookDirectory[]]
Get["func"]


But after that cell is evaluated, still evaluating

f[x]


unfortunately reveals the symbolic definition of f.

Is it possible somehow to hide the symbolic definition yet be able to evaluate f at arbitrary numeric input?

-
Hmm... does it really show up even in a fresh mma session? Are you sure that you're loading the encoded file and not the plain text .m file (I think just Get["func"] will load the m file)? I haven't tried it yet since I don't have a free kernel right now, but it seems like what you're suggesting should work... –  rm -rf Sep 14 '13 at 17:25
Ohh... never mind. I see what your problem is. Just define f as f[x_?NumericQ] and that should fix it. –  rm -rf Sep 14 '13 at 17:27
@rm -rf: Yes, I just realized that's the way. For the record, please make that an answer. Or at least its part of the way. Clearly I need to take an additional step lest the more clever use try something like f[Pi] and begin to get a hint of the definition. Namely, use f[x_?NumericQ] := N[Exp[-x] Cos[2x]. –  murray Sep 14 '13 at 17:43
Ah, in that case you can just use _?NumberQ. I will make that an answer. –  rm -rf Sep 14 '13 at 18:01

What you're suggesting seems fine to me. The only additional step necessary is to restrict the definition of f to only numeric values (i.e., keep it unevaluated for symbolic input). The way to do that would be to use the pattern test NumericQ on the input as:

Clear@f
f[x_?NumericQ] := Exp[-x] Cos[2 x]


which will not evaluate for input such as f[x]. However, as you note, it will evaluate for symbolic forms of numerical values, such as Pi, E, GoldenRatio, etc., which can give the user a hint to the underlying form:

f /@ {E, Pi, GoldenRatio}
(* {E^-E Cos[2 E], E^-Pi, E^-GoldenRatio Cos[2 GoldenRatio]} *)


There are two solutions here:

• If you want to provide a numerical output, you could just apply N on the RHS in the definition

Clear@f
f[x_?NumericQ] := N[Exp[-x] Cos[2 x]]

f /@ {E, Pi, GoldenRatio}
(* {0.0437182, 0.0432139, -0.197404} *)

• If you want to keep it unevaluated, you could use NumberQ to restrict the pattern:

Clear@f
f[x_?NumberQ] := Exp[-x] Cos[2 x]

f /@ {E, Pi, GoldenRatio}
(* {f[E], f[Pi], f[GoldenRatio]} *)


If your user is smart enough, they can still work around this by tricking f to believe that a symbol x is also a numeric value (example using the NumericQ definition of f):

NumericQ[x] = True;
f[x]
(* 2.71828^(-1. x) Cos[2. x] *)


You can do the same with NumberQ after unprotecting it. To avoid this, you can include a dummy definition for _Symbol:

f[x_Symbol] := Null

-
-f: Yes, I already noted I'll want to wrap with N so as to hinder "decoding" the function by plugging in symbolic numerical entities such as Pi. –  murray Sep 14 '13 at 21:17
@murray Please also see my update. –  rm -rf Sep 14 '13 at 22:27
Unfortunately, I don't think the ploy f[x_Symbol] := Null works to avoid the NumericQ[x] = True attack. When I do that and then evaluate f[x] I obtain result 2.71828^(1. x) Cos[2. x]. –  murray Sep 16 '13 at 18:48
@murray Ah, I wasn't explicit — the definition for _Symbol should come before that for _?NumericQ. It won't work if you place it after. –  rm -rf Sep 16 '13 at 18:58
I wondered about the order. I knew that "general" rules are applied only after "particular case" rules, but I hadn't recalled seeing an explicit statement that otherwise it's the order that counts.I find it now, in the final paragraph of the exposition in tutorial/TheOrderingOf Definitions`: "Whenever the appropriate ordering is not clear, Mathematica stores rules in the order you give them." –  murray Sep 17 '13 at 0:23