Skip to main content

What are recommended guidelines for developing packages?


This might be of general interest – I have different questions regarding naming conventions, contexts, subcontexts, shadowing, etc., but I do feel that they are closely related, thus I don't really want to split this post into three.




  1. Naming
    What is the best method to name the package file, the package context, the directory of package files (or a more complex hierarchy of these files)? Which of these names must be the same? I got confused several times before, and though I always manage to solve a situation, I don't feel like I have a good understanding on how these things work.





  2. Shadowing
    When there are interrelated packages with different contexts where some symbols appear in all of these contexts then - when calling contexts in the same session - usually shadowing messages appear. This is useful, when such symbols have different definitions and are unintentionally named the same way, but not, in the following case. If someone has a newly introduced function option, like Verbose, which doesn't have an OwnValue, then it is totally unnecessary to invoke shadowing messages, as no call of Verbose could do any harm. There still might be difference in the overall description of Verbose in two packages (even when all OwnValues, DownValues, etc. are the same), for example their usage messages might differ, as different functions would utilize the Verbose option in the different packages.


    What is the best way to deal with these things? Should a Common.m package be introduced, and all the related packages be moved under a common context-name and/or directory? Do they have to be in the same directory?




  3. Grouping and sub-contexts
    Following point 2, when is it useful to introduce sub-contexts (e.g. myContext`format` and myContext`content`)? Should these be split into different files? How should these files be named? Is it necessary then to include a Common.m too or is it just for convenience? What should be kept in Common.m?





Answer




Part of what you are asking is of course a matter of taste and habits, but here are my 2 cents:


1) if you want Mathematica to find your package files with a Needs or Get their context names must agree with the hierarchy of directories and filenames. I don't see any good reasons to diverge from that standard convention. For complex packages with many files you will also typically have a Kernel-subdirectory with an init.m, but I think these things are relatively well documented.


2) My personal opinion is that using symbols for option names is asking for exactly these kind of problems. Obviously at least some of the WRI personnel thinks the same, since in later versions there are more and more options that accept strings as names and the new way to work with options also full supports this. If you are worried about cluttering your code with too many pairs of "", note that this will work alright:


Options[f] = {"Verbose" -> False}

f[OptionsPattern[]] := (If[OptionValue["Verbose"],
Print["I'm so verbose!"]]; RandomReal[])

f[Verbose -> True]


or even:


f[someothercontext`Verbose -> True]

What you loose is the possibility to have a usage message bound to the option name, but as you have noticed if there are more than one function using the same option name, the usage message is of limited use anyway and the details must be explained in the documentation of the function, not the option. WRI has the same problem, obviously: At least I don't think that this usage is of very much help:


?Method

Method is an option for various algorithm-intensive functions that specifies what internal methods they should use.


3) Introducing sub-contexts is useful when things get more complex and parts of the whole can be split up in more or less independent parts. Of course giving these parts names that make it easy to recognize what they provide is a good idea, but I think that's so obvious that I doubt I fully understand that part of your question. If you want these parts to be loadable without the other parts, you must split them in different files, otherwise it's up to you from the technical viewpoint. From the code organization point of view I would think that if it makes sense to split your packages in separate contexts, it usually is also a good idea to split them into separate files. That becomes even more important if several people work on the various parts, but I feel there is not much Mathematica code written that way (except within WRI). Of course it's not necessary to include a Common.m, but as you have mentioned it's a good approach to collect all symbols that the various parts share into one common context/file, and Common.m (myPackage`Common`) is a common convention that is also used by WRI, so I'd stick with it. On the other hand I would consider it as a good design of your package when you don't need a Common.m, since then you obviously managed to really split your package in independent parts.


Comments

Popular posts from this blog

mathematical optimization - Minimizing using indices, error: Part::pkspec1: The expression cannot be used as a part specification

I want to use Minimize where the variables to minimize are indices pointing into an array. Here a MWE that hopefully shows what my problem is. vars = u@# & /@ Range[3]; cons = Flatten@ { Table[(u[j] != #) & /@ vars[[j + 1 ;; -1]], {j, 1, 3 - 1}], 1 vec1 = {1, 2, 3}; vec2 = {1, 2, 3}; Minimize[{Total@((vec1[[#]] - vec2[[u[#]]])^2 & /@ Range[1, 3]), cons}, vars, Integers] The error I get: Part::pkspec1: The expression u[1] cannot be used as a part specification. >> Answer Ok, it seems that one can get around Mathematica trying to evaluate vec2[[u[1]]] too early by using the function Indexed[vec2,u[1]] . The working MWE would then look like the following: vars = u@# & /@ Range[3]; cons = Flatten@{ Table[(u[j] != #) & /@ vars[[j + 1 ;; -1]], {j, 1, 3 - 1}], 1 vec1 = {1, 2, 3}; vec2 = {1, 2, 3}; NMinimize[ {Total@((vec1[[#]] - Indexed[vec2, u[#]])^2 & /@ R...

functions - Get leading series expansion term?

Given a function f[x] , I would like to have a function leadingSeries that returns just the leading term in the series around x=0 . For example: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x)] x and leadingSeries[(1/x + 2 + (1 - 1/x^3)/4)/(4 + x)] -(1/(16 x^3)) Is there such a function in Mathematica? Or maybe one can implement it efficiently? EDIT I finally went with the following implementation, based on Carl Woll 's answer: lds[ex_,x_]:=( (ex/.x->(x+O[x]^2))/.SeriesData[U_,Z_,L_List,Mi_,Ma_,De_]:>SeriesData[U,Z,{L[[1]]},Mi,Mi+1,De]//Quiet//Normal) The advantage is, that this one also properly works with functions whose leading term is a constant: lds[Exp[x],x] 1 Answer Update 1 Updated to eliminate SeriesData and to not return additional terms Perhaps you could use: leadingSeries[expr_, x_] := Normal[expr /. x->(x+O[x]^2) /. a_List :> Take[a, 1]] Then for your examples: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x), x] leadingSeries[Exp[x], x] leadingSeries[(1/x + 2 + (1 - 1/x...

What is and isn't a valid variable specification for Manipulate?

I have an expression whose terms have arguments (representing subscripts), like this: myExpr = A[0] + V[1,T] I would like to put it inside a Manipulate to see its value as I move around the parameters. (The goal is eventually to plot it wrt one of the variables inside.) However, Mathematica complains when I set V[1,T] as a manipulated variable: Manipulate[Evaluate[myExpr], {A[0], 0, 1}, {V[1, T], 0, 1}] (*Manipulate::vsform: Manipulate argument {V[1,T],0,1} does not have the correct form for a variable specification. >> *) As a workaround, if I get rid of the symbol T inside the argument, it works fine: Manipulate[ Evaluate[myExpr /. T -> 15], {A[0], 0, 1}, {V[1, 15], 0, 1}] Why this behavior? Can anyone point me to the documentation that says what counts as a valid variable? And is there a way to get Manpiulate to accept an expression with a symbolic argument as a variable? Investigations I've done so far: I tried using variableQ from this answer , but it says V[1...