Making It All Work
George E. Hrabovsky
MAST
Introduction
In this lesson we will explore how to make your own packages and larger programs. Examine some alternative developer environments. And then we will discuss debugging and testing.
We will begin with what a package is. How to load a package effectively. Then we will discuss how to write a package of your own.
A more recent development is the paclet. I will explain what a paclet is. Where you can find new paclets. How to write a paclet.
We will then turn to discussing developer environments and tools that are available.
We will end our discussion with exploring some of the tools available for debugging and testing.
Larger Programs and Packages
What is a package? A package is a collection of functions that form an extension to the MMA/WL system. Many are user-created. For example, if you find yourself programming the same thing across multiple notebooks, you might consider bringing the similar functions into a package that you can create. Many packages have a theme, for example the free package xAct is devoted to tensor analysis and differential geometry, I use it all the time for general relativity.
There are two commands to use to load a package into active memory. The first is preferred, but there is no shortcut for it. You write Needs[“context`”]. This adds the context to the current $ContextPath. What does that accomplish? It allows you to access all of the built-in symbols of the package. Should you find the context cumbersome when you refer to it later, you can create an alias for it in the current instance by writing Needs[“context`”->”alias`”].
What is wrong with using Get? It seems easier to write <<context` than Needs[“Context`”]. The problem with Get is that it doesn’t place all symbols under one hat, you might have two function names that are identical and then you have a shadowing conflict that will eventually cause problems. Use Needs instead.
What is the advantage of using a package? If what you are doing is a small task, then there is no advantage. If you are going to be using a lot of new functions, then a package is the way to go.
How do I write a package? Go to the File Menu, then choose New then choose Package.
Here is an example from the documentation. It is a short package.
BeginPackage["Collatz`"]
Collatz::usage =
"Collatz[n] gives a list of the iterates in the 3n+1 problem,
starting from n. The conjecture is that this sequence always
terminates."
Begin["`Private`"]
Collatz[1] := {1}
Collatz[n_Integer] := Prepend[Collatz[3 n + 1], n] /; OddQ[n] && n > 0
Collatz[n_Integer] := Prepend[Collatz[n/2], n] /; EvenQ[n] && n > 0
End[ ]
EndPackage[ ]
You start by putting it all into a your new package notebook. Then you write the command BeginPackage[“Context`”]. This tells MMA/WL the context you are creating.
The next step is to list the usage statements for all of the functions you are making. This will produce what you see if you write ?function name. You write function_name::usage=”help listing”
Once you have written out the help description for each, you now have to tell MMA/WL: to begin the package. Begin[“`Private`”] tells the system that you are now entering a private subcontext that will contain all of the code that the user will not see.
You then write all of the necessary code to make the functions work as you want them to.
You enter the Private context with the End[] command. Then you tell the system that the package is finished with the EndPackage[] command.
Save your work. Make sure your package name ends with a .wl.
Paclets
What is a paclet? It is tempting to think of a paclet as a miniature package. It might be that, no question. It can also include packages, links, stylesheets, palettes, system settings, documentation, and even data.
Where do we find paclets? Some are built into the system, some are in the cloud, some are in the paclet server at Wolfram Research, some are stored at GitHub. There is talk of a paclet repository in the future.
We can use the command PacletSites[] to list where we can get paclets from.
Some paclets are built in to MMA/WL. Here is a paclet that handles web searching.
Expanding the box tells you where to find the paclet on your system. We can see its properties.
Here we find the paclets installed in the current version.
Here we determine how many are present that are not compatible.
So the number of paclets that are valid will be here.
Here they are.
How do we load a paclet?
We can also uninstall it.
How do I write a paclet? It is very similar to writing a package, though there can be more to it. This is taken from the tech note “Creating Paclets” included in the documentation.
We begin by loading the PackletTools` package.
We then create a blank object that will become our paclet.
Let’s take a look at what we have right now.
This opens a system folder in another window that described the files found in this new directory. Note that we have a WL file, so the blank paclet is there. Here is what we find if we open the paclet.
If we open the Kernel subfolder, we can click on the MyPaclet to get the structure of the package.
This is a template that you can expand this as you like to build the functionality of your paclet. Otherwise it behaves just like a package. If I included this directory in the directory path I can open this paclet as I would any package.
Integrated Developer Environments
What is an integrated developer environment (IDE)? Any application that you use to write code is an IDE. Before IDEs became prevalent code was produced in text editors. A modern IDE has tools for developing, running, and testing code. Outside of MMA there are three widely used IDEs: Visual Studio, Eclipse, and Android Studio.
The notebook is a developer environment. It has color codes that identify code fragments and it points out errors in coding. So the notebook is the fundamental IDE.
Eclipse is a popular and free IDE available from the website https://www.eclipse.org/ . Eclipse works by loading a number of subsystems along with a small runtime engine. The interface is through a desktop graphical IDE. There are many modules that you can plug in. As with any IDE you can write your code, debug it, and then run your code.
Wolfram Workbench is an Eclipse plug-in that allows you to develop MMA/WL code in Eclipse. It is a free download. This is an alternative to the traditional notebook IDE.
Another free resource is the Wolfram Engine for developers. This being free, you can link it to the Wolfram Workbench and code in the WL for free.
There are other IDE plug-ins too. You can pick the plug-in for the IDE you like.
So, with the free Wolfram Player, this brings the entire panoply of WL/MMA to the hobbyist for free.
Debugging
What is debugging? Debugging is the process of locating and removing errors, bugs, in coding. It is possible that the term bug comes from a notebook of noted computer scientist Admiral Grace Hopper when a moth was discovered in a Mark II computer relay in 1947. They removed the bug and taped it into her notebook. This might have been the first debugging of a computer system... Debugging is performed by software developers to make sure their software is error-free at the point of development.
Software testing is a formal part of a developer cycle within the larger topic of software engineering. This usually employs a group of software testers who employ a testing framework. This is pretty far removed from a code monkey cobbling together a program for a specific purpose. This is more in the realm of developing a professional product for public or private release. As we will see, MMA/WL has such a framework in place.
So, what do we do when an error shows up? Say we do something like this.
Note the structure of the warning message: . If you click on the ellipses button you get a popup display with two interesting items. The first is Show Stack Trace. The second is Power::infy. If you select the first option you get a stack trace of the evolution of the evaluation.
This is in reverse order. The evaluation begins with the last cell.
This is just the command we entered. The next cell performs the first step.
Then it evaluates until it finds the problem.
Then it gives the message generated.
You can trace each step in an evaluation by using the Trace[] command.
This is more readable in TableForm.
|
||||||||||||||||
|
1 (-1) | -1 | ||||||||||||||
|
1 ComplexInfinity | ComplexInfinity | ||||||||||||||
|
1 1 | 1 | ||||||||||||||
|
||||||||||||||||
You can click on the other part, Power::infy, a new window opens up with detailed information about the error. There might even be suggestions for how to avoid the error.
Sometimes, as is the case here, the error message is correct, but we want to ignore it. We use Quiet.
If your code is not working right, but it is not throwing an error you can get a clue by dynamically monitoring one or more variables as they change. This example is based on the documentation.
Sometimes it is useful to know at what iteration a function goes off the rails. Here is an example taken from the documentation.
Say we want to see how far i gets.
In recent versions there are two new features in the Evaluation Menu. Analyze Notebook and Analyze Cells. Here is an example of code. If you highlight the cell and go to Analyze Cell we will see if MMA/WL can catch the error.
You can perform such a static analysis on any code cell or on an entire notebook.
You can also run an official test on a single function.
We can get a report on how it failed.
You would then perform the code analysis to find out what happened. You could then correct it.
You can create a notebook specifically to test code. You begin with the File Menu. Choose New. Choose Programmatic Notebook. Then choose Testing Notebook. You select New to produce a test field. Follow the directions. There is an excellent example in the Tech Note “Using the Testing Framework” included with the documentation.