17
$\begingroup$

I have created a Mathematica package that manipulates various types of input physics data into a common form of output data for further analysis. To make this process more efficient and manageable, I assign each specific set of data a different head and define the manipulation functions differently (as necessary) for each of the various heads. For example,

getX[data_AA] := data[[1]];
getY[data_AA] := data[[2]];
getZ[data_AA] := data[[3]];
getR[data_AA] := Module[{x=getX[data],y=getY[data]},Return[x^2+y^2]]
...and so on...

getR[data_BB] := data[[1]];
getPhi[data_BB] := data[[2]];
getX[data_BB] := Module[{r=getR[data],phi=getPhi[data]},Return[r*Cos[phi]]]
...and so on...

getX[data_CC] := data[[5]];
...and so on...

Accordingly, I have written functions that change the heads of the data from List (since the data are imported from files into arrays) to their respective heads so that the data can then be used as arguments in the manipulation functions like the examples above: for example,

makeAA[AAdata_] := Return[AAdata /. List -> AA]

Because I want this to all be done internally, so that one cannot simply initialize a random object in a notebook with a global head of AA and then use the manipulation functions on that arbitrarily created object (see Note below), I have made the heads private members of the module. If the data is returned, however, by the function, say,

getAAdata[filename_]

then it is displayed as

PackageName`Private`AA[PackageName`Private`AA[particle 1 data],PackageName`Private`AA[particle 2 data],...,PackageName`Private`AA[particle N data]]

instead of the more concise and, therefore, more desirable

AA[AA[particle 1 data],AA[particle 2 data],...,AA[particle N data]]

(this is especially a problem when dealing with further nested arrays).

So the question is: how can I get private objects (heads, variables, etc.) to display in outputted data without the cumbersome and cluttering "PackageName`Private`" prefix?

Note: it is not sufficient to list the heads in the public part of the package because then, even though it would solve the above problem, it would introduce an additional problem that one would be able to initialize arbitrary objects with those heads -- say, test=AA[2.1,3.2,5.4,2.3] -- and then call getX[test], which will then carry out the evaluation as it would any object with head AA. I want to reserve creating objects with those heads to other functions in the package (such as makeAA; see above).


This problem also shows up if I don't explicitly write a usage description/tag for a function and try to get information on the function by doing

?Function

-- all the arguments and local variables are written with the "PackageName`Private`" prefix, making it rather difficult to read the body of the function.

Thank you very much for your help!

$\endgroup$
3
  • $\begingroup$ Is this a duplicate? mathematica.stackexchange.com/q/1742/121 $\endgroup$
    – Mr.Wizard
    Jun 27, 2012 at 6:39
  • $\begingroup$ Related: stackoverflow.com/q/2744624/618728 $\endgroup$
    – Mr.Wizard
    Jun 27, 2012 at 7:29
  • $\begingroup$ @Mr.Wizard -- The first link that you provided above is indeed an answer to my second question about obtaining context-free information/definitions of functions in my package. I believe that the main question I had, however, is not addressed by either of the above links, but is instead beautifully answered by Oleksandr below. Would you agree? $\endgroup$ Jun 27, 2012 at 15:58

3 Answers 3

11
$\begingroup$

A more object-oriented approach may be helpful here. For example:

BeginPackage["example`"];
thing;
new;
Begin["`Private`"];
thing /: new[thing[contents_]] :=
  Module[{thing},
   (* Supported operations: *)
   thing /: Plus[thing[x_], y_] := thing[x + y];
   thing /: Times[thing[x_], y_] := thing[x y];
   (* Example invalid operation: *)
   thing /: Power[_thing, _] := $Failed;
   (* Format value: *)
   thing /: MakeBoxes[thing, StandardForm] = InterpretationBox["thing", thing];
   (* Return symbol: *)
   thing[contents]
  ];
End[];
EndPackage[];

Now we can write, e.g,

myThing = new@thing[73];
4 myThing + 3

which gives:

thing[295] (* == thing[4 * 73 + 3] *)

However, despite the standard form (which can also be copied and pasted from output to input thanks to the InterpretationBox), the internal representation is quite different:

% // InputForm
(* -> thing$576[295] *)

As a result we can't just conjure things up without invoking new, as the methods defined on real things simply won't exist in that case:

myNewThing = thing[48];
myNewThing + 17
(* 17 + thing[48] *)

Strictly speaking, the format value would have been enough to answer your question as stated. However, it seems like an object oriented approach is quite a natural fit for what you're probably trying to achieve here, so the extra effort may be worthwhile for maintainability and robustness reasons if you intend to have a lot of different objects each with their own private methods and/or internal state.

$\endgroup$
2
  • 1
    $\begingroup$ Hi Oleksandr! MakeBoxes and InterpretationBox were exactly what I was looking for; the additional information about making Mathematica function more like an object-oriented language was the cherry on top! Thank you very much! $\endgroup$ Jun 27, 2012 at 15:47
  • 1
    $\begingroup$ @PhysicsCodingEnthusiast: you're very welcome. I think it's also worth noting if you use this object-oriented approach, you'll also be able to overload Definition (as suggested by R.M) without having to make global modifications. Indeed, making such modifications as part of a package is a usually considered to be a very bad idea, because who knows what combination of packages users might load. $\endgroup$ Jun 28, 2012 at 21:46
8
$\begingroup$

Try this:

Begin["PackageName`Private`"];
?`*
End[];

which puts you in the private context when you execute ?`*. Also, note the grave mark (`) in ?`*, it ensures that the wildcard (*) is only applied to the current context not your entire $ContextPath. Incidentally, this is the same reason that Private in Begin["`Private`"] is also preceded by a grave mark, it ensures that it is a sub-context of the package context.


The simplest way, though, is simply to type

?PackageName`Private`*

which will not display the context path of the variables.

$\endgroup$
10
  • $\begingroup$ Hi rcollyer; thanks for your reply! Perhaps I should have been more explicit in stating that I was hoping to be able to add something to my package itself to suppress the "PackageNamePrivate" context prefix, at least for my self-defined heads of the various datasets. The only command I would want anyone to have to invoke in a Mathematica notebook/script would be the Get[Package.m] command, without having to worry about invoking Begin["PackageNamePrivate"]. Is that possible? $\endgroup$ Jun 27, 2012 at 1:57
  • $\begingroup$ The inner context is there to hide the implementation from casual inspection. In Mathematica, this isn't a strict barrier, but it is okay for its purpose. Outside of that, but within the package context itself, you expose the symbols you want the rest of the world to see usually through a symbol::usage string. Using it that way, Get[package.m] works just fine, and as long as your careful the things in the private context don't leak out. (But, you've read that question.) How does your usage requirements differ from this? $\endgroup$
    – rcollyer
    Jun 27, 2012 at 2:05
  • $\begingroup$ That functionality is mostly okay for me, as well. The only problem I have with that is when I have a function that outputs data with one of my self-defined private heads: for example, a function like getAAdata[filename_] will return data in the form AA[AA[particle 1 data],AA[particle 2 data],....,AA[particle N data]]. But the heads will, of course, not be displayed simply as AA, but rather as PackageName`Private`AA, so that the output will look rather messy. $\endgroup$ Jun 27, 2012 at 2:14
  • $\begingroup$ Of course, I could always convert the head back to List, so that the data is presented in nicely in array form, but I'm just curious. Overall, it's not the biggest problem in the world, but I do appreciate your humoring me! $\endgroup$ Jun 27, 2012 at 2:16
  • $\begingroup$ Also, sorry for the numerous comment postings, deletions, and edits -- I'm still getting used to the site! $\endgroup$ Jun 27, 2012 at 2:17
4
$\begingroup$

The only way to call a function/variable in a package without using the full context is to make it public, which is typically done with usage messages immediately after the BeginPackage["Package`"] and before Begin["Private`"].

To me, it seems like you just want to be able to view the definitions, etc. without it looking messy with all the context information. To do that, here's a simple way to add a definition to, uhm, Definition that does this. Include this in your package:

Unprotect@Definition;
Definition[x_Symbol] /; StringMatchQ[Context[x], "Package`" ~~ ___] := 
    StringReplace[ToString@FullDefinition[x], 
        (WordCharacter .. ~~ DigitCharacter ... ~~ "`") .. ~~ s_ :> s
    ];
Protect@Definition;

Now, all functions in your package will not have the full context displayed when you call ?foo. Note that it is not really Definition, as I'm using FullDefinition, which also gives you the definitions of all symbols foo depends on. This is only for convenience sake, so that you can still use ?. If you strictly want only Definition, create a function myDefinition instead (otherwise you'll end up with a recursion) that uses the above example with Definition instead of FullDefinition (I didn't want to mess with the parsing of ? since it's also used in pattern tests and could break a lot of things subtly).

Here's an example of it at work:

enter image description here

In the above code, I strip away all context information. If you want to strip only Package`Private`, then you can modify the StringReplace part accordingly.

$\endgroup$
3
  • 1
    $\begingroup$ Thanks R.M; this was a great answer to my second question -- I will definitely be using this! I wish there were a way to accept more than one answer for this question, since it had two (related) parts to it. Out of curiosity, is it commonplace to modify default Mathematica functions/behaviors like you have done with Definition above? $\endgroup$ Jun 27, 2012 at 15:52
  • $\begingroup$ @PhysicsCodingEnthusiast you can't accept more than one answer, but you can offer bounties for answers that are good and deserve recognition, but are not accepted. Unfortunately, they require 75 rep, but I imagine you'll get there soon. $\endgroup$
    – rcollyer
    Jun 27, 2012 at 16:56
  • $\begingroup$ @PhysicsCodingEnthusiast It depends... I would normally not overload/redefine built-ins, unless there's a strong need for it and even then only if it is reasonably safe to do so. In this case, the additional definition is very narrow in scope and in the tests I did, I didn't come across any issues. However, there are some functions that I wouldn't touch, no matter what... things like Set for example, which are fundamental. As I said, if you don't mind not using ?, then it might be better to use a custom definition and even assign it to an unused prefix operator $\endgroup$
    – rm -rf
    Jun 27, 2012 at 17:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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