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'm trying to create a function (in a package) to import a lot of data and create a symbol with UpValues to return specific results about the data. I've got it working fine in a regular notebook, but when I define the function within a package I can't get it to work properly.

A simple example of my problem:

TestPackage.m:

BeginPackage["TestPackage`"];

testFunction::usage= "testFunction[] does all kind of interesting things.";

Begin["`Private`"]

testFunction[name_Symbol]:=
 Module[{},(
  ClearAll[name];
  UpValues[name]=
   {
    test[name]->"hello!"
   };
  Protect[name];
 )]

End[]

EndPackage[]

I then call the function in a regular notebook:

Needs["TestPackage`", "/path/to/TestPackage.m"]

testFunction[a]
  • test[a] returns test[a]
  • and TestPackage`Private`test[a] returns the expected "hello!"

How do I change testFunction so that test[a] also returns "hello!"?

share|improve this question
1  
Welcome to Mathematica! I cannot tell you how much I appreciate your efforts in correctly marking up your question. Although, I did fix the issue with context names, which involved wrapping the whole thing in double grave marks, not single ones, but most people are not aware of that. I would encourage you to register your account so you can more fully participate here. Again, welcome, and I hope to see you here again. –  rcollyer Dec 6 '12 at 20:43
    
Thanks for the welcome @rcollyer! And for fixing my source, I couldn't figure out how to do that. –  jlmr Dec 6 '12 at 21:01
    
You're welcome. Three questions. 1. Why are you setting UpValues[...] directly, instead of using either UpSet (^=) or TagSet (name /: test[name] = ...) directly? 2. Have you tried setting a usage string on test, or if you have considered that why doesn't it do what you need? 3. Do you have any purpose for Module other than to provide convenient structure, as it doesn't do anything in your code? –  rcollyer Dec 6 '12 at 21:12
    
2 answers and 1 question in return: 1. I didn't know about UpSet. It seems to produce the same results though. What's the difference between setting the values directly and using UpSet? 2. Where would I set a usage string on test? In the function definition or somewhere else? 3. It's true that Module doesn't serve any purpose here. It does however in the actual function I'm trying to write, which also needs a couple of temporary variables to store results. I thought it wise to include Module, since it also deals with scopes. –  jlmr Dec 6 '12 at 21:16
    
1. There's no difference between what you're doing and UpSet, just that UpSet is the common way of accomplishing what you're doing, so more readily recognizable. 2. Set the usage string in the preamble of the package like you do for testFunction. 3. I figured that was the reason, but I encountered at least one person who believed it was performing localization while using it like in your code. –  rcollyer Dec 6 '12 at 21:45
show 1 more comment

2 Answers

up vote 5 down vote accepted

The explanation can be found in the doc to BeginPackage and Begin

  • BeginPackage["context`"] makes context` and System`the only active contexts.
  • Begin["context`"] resets the current context.

Therefore, at the moment you first mention the symbol test it is not created it in the Global context. This can be seen from you (simplified) example

BeginPackage["TestPackage`"];
testFunction::usage = 
  "testFunction[] does all kind of interesting things.";
Begin["`Private`"];
testFunction[name_Symbol] := name /: test[name] := "hello!";
End[];
EndPackage[]

testFunction[a]
UpValues[a]

(* {HoldPattern[TestPackage`Private`test[a]] :> "hello!"} *)

beside giving test a ::usage message, you can give the context explicitly

testFunction[name_Symbol] := name /: Global`test[name] := "hello!";

Further note

  • I don't see why you use Module because you don't localize any variable. And if you want to input a sequence of commands, divided by ; (called a CompoundExpression) you can simply wrap it in parenthesis, as you did.
  • Your combination of ClearAll and Protect is such that you can call testFunction on a given Symbol only one time. On the second call you get messages since ClearAll cannot clear a protected symbol. What is the intention behind this?
share|improve this answer
    
Thanks for your answer. 1. Adding a ::usage message fixes the problem. I won't set the context explicitly, because I also want to call the function from other contexts than Global` . 2. Module is not used here, but will be used in the full package. 3. I used Protect because it prevents from accidentally setting a value to name which prevents the UpValues form working correctly. If there is a better way, I'd like to hear it. Thanks again! –  jlmr Dec 7 '12 at 9:03
    
@jlmr you may wish to Unprotect the Symbol at the beginning of your module. –  Mr.Wizard Dec 7 '12 at 12:20
    
@Mr.Wizard thanks for the tip! –  jlmr Dec 7 '12 at 12:40
add comment

You should export the test symbol, ie define it between BeginPackage["TestPackage"] and Begin["Private`"], for example by giving a usage to test.

test::usage = "test[name] returns ..."
(*or just*) test;

for your definition, as said already in comments, I would use

test[name] ^= "hello";

My answer to this post contains many application of UpValues, it could interest you: Struct equivalent in Mathematica?

share|improve this answer
    
Thanks, this fixes it! –  jlmr Dec 7 '12 at 9:03
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.