Table of Contents

The PrintMacroJ macro-expander
The print macro
     An example
     Details of the macro-expansion
     How I wrote and ran CheckSort
     Putting javac into the path
     Download, install, uninstall
     What deepToString can do and cannot do
The pri and pr and prin macros
The deleteUnderscores macro
The doubleBackslashes macro
The milliseconds macro
The swap macro
Macros for functions
     The stack
     The yourInterface macro
     What became of myClass and yourClass?
     Composing two functions
     Implementing two or more interfaces
     Two other files using functions
     Using a throws clause
     The Metropolis algorithm: probability
     The Metropolis algorithm: statistics
     The ShadedContours program
The unclass.bat file
The AllPriUnJava.pri file
The AllPri2Java.pri file
The PriUpdateJava.pri file
The FileNames.pri file
Overloading operators for primitives and immutables
     RatioStatics
     BigDecimalStatics
     DoubleStatics
     Import static and the compPivMat package
     Let and Dac
Overloading operators for mutables
     ComplexMutate
     Mutate and Dac
The for and next macros
The firstly and lastly macros
Lonely curly braces and lonelyCurly
The go and stop macros
The enforce and forbid macros
The define and unDefine macros
The keyValue and unKeyValue macros
The cross and dot and dyad operators
The setq and dotimes and right-paren macros
Changes
License, revision date, and e-mail address

The PrintMacroJ macro-expander

I corrected a big bug in PrintMacroJ on 1 August 2007. Users who last downloaded it on or before that date are respectfully advised to click on Changes.

The easiest way to debug Fortran and Basic is to put in many little print statements, and then to take them out when they are no longer needed. In Java™, System.out.println statements are far from little. The quick way to solve the problem is by building a macro-expanding preprocessor. I took advantage of the split method of Java 1.4 and later and the deepToString method of Java 1.5 and later to write something very short. I needed a name for my work, so I looked in Google and did not find PrintMacroJ anywhere, so that is the name that I use.

Having written a preprocessor, I added a few more macros for other things besides printing. I put in a macro to help with regular expressions, a macro to delete underscores in numerical fields as in Ruby, a swap macro, a macro for milliseconds, a few macros to make methods look more like functions, and some macros for overloading operators.

I respectfully invite everybody to add new macros to PrintMacroJ by merely adding new else if paragraphs to the manage method of the Print class. It is the only class in the Print.java file. Please note that the Print.manage method is called from three files: Print.java, AllPri2Java.pri, and Update.pri .
To top

The print macro

Sun’s Java computer language lacks an easy print statement. I mean something like
print   eye   x
(Tripling the blanks is for easier reading. Single blanks will separate just as well.) When I am debugging a one-thread number-crunching console program, that is the kind of statement that I want. Indeed, when I am debugging, I want the statement to print out not only the numerical value but also the formula from which it came. I want the print statement to work not only primitives and objects having toString methods but also arrays, including arrays of arrays, and so on. Maybe other programmers do, too.

Java 5 and later makes it easy to build such a thing oneself. I have written a macro-expander, whose source file is Print.java, having a macro named print to make use of the java.util.Arrays.deepToString static method. That is, the print macro writes a call to that method into the output file.

PrintMacroJ contains other macros besides print. The macro-expander splits each line of the input file on blanks and tabs into tokens having no white-space in them. If the left-most token of the line is recognized as the name of a macro, that macro is used. Otherwise, the line is passed through unchanged.
To top

An example

For a concrete example, I have written a file called CheckSort.pri having some print statements. This file is meant to repeatedly create a float array, fill it with random numbers, print the array, sort the numbers, and print the array again. This is something often done in numerical analysis, to see if the programmer understands correctly what Math.random and java.util.Arrays.sort do.

This file is expanded to a file named CheckSort.java which can then be compiled by javac and executed by java. The reader who looks at CheckSort.java will notice how monstrous and unreadable the print macros have grown.

Here is what the program printed when it was run:

eye, 0, x, [0.29298615, 0.72581846, 0.06552495, 0.20124246]
eye, 0, x, [0.06552495, 0.20124246, 0.29298615, 0.72581846]

eye, 1, x, [0.17495424, 0.23389111, 0.96421194, 0.59524924]
eye, 1, x, [0.17495424, 0.23389111, 0.59524924, 0.96421194]

eye, 2, x, [0.6218451, 0.81528014, 0.9022297, 0.20639604]
eye, 2, x, [0.20639604, 0.6218451, 0.81528014, 0.9022297]

eye, 3, x, [0.06735267, 0.06981697, 0.3623766, 0.65278155]
eye, 3, x, [0.06735267, 0.06981697, 0.3623766, 0.65278155]

eye, 4, x, [0.4803864, 0.9918647, 0.97115314, 0.78323096]
eye, 4, x, [0.4803864, 0.78323096, 0.97115314, 0.9918647]

eye, 5, x, [0.40152532, 0.057389356, 0.98135525, 0.7244261]
eye, 5, x, [0.057389356, 0.40152532, 0.7244261, 0.98135525]

eye, 6, x, [0.9820171, 0.0944072, 0.45101392, 0.6934208]
eye, 6, x, [0.0944072, 0.45101392, 0.6934208, 0.9820171]
Without the print macro, this would have been much less convenient to program.
To top

Details of the macro-expansion

Let me explain how the macro-expansion was done. If the left-most token is print, then the other tokens are understood to be arguments. There are not any commas between the arguments. There is no semicolon at the end of the call. Each argument is used twice, with and without quotes around it. When it gets quoted, any quote marks and backslashes already in the token are protected by backslashes on their lefts.

All these quoted and unquoted arguments are connected with commas between them. Then curly braces are put on the left and right. Then this formula is used to initialize a new Object[]. Then this Object[] is handed to the deepToString method, as I have said. Then the resulting left-most and right-most square brackets are removed by a regular expression. Then System.out.println is used to actually do the printing. Another look at CheckSort.java may make this clearer.

The CheckSort.pri and CheckSort.java files have exactly the same number of lines, because Print.java always outputs exactly one line for every line it inputs. This is necessary for understanding javac’s diagnostics.
To top

How I wrote and ran CheckSort

To write and run the CheckSort program I opened a Dos box on my Windows computer, made sure that javac was in my path, and typed on the command line
set left=CheckSort
Then I wrote the CheckSort.pri file in a simple Windows editor and saved it. Then I clicked back to the Dos box and typed
pri
to start the pri.bat batch file. That batch file executed javac and java for me, to save a lot of typing. Of course, my batch file is for Dos, and the user may be on some other platform. I think that changing pri.bat to use Unix or Linux may be easy. I have no idea how to change it to use Macintosh.

I have in June 2007 changed the pri.bat file to use the -server modifier on the last line. This is meant to increase run-time speed, but sometimes it makes the program go slower.
To top

Putting javac into the path

Linux and Unix users already know all about paths, so this section is for Microsoft Windows users. (I do not know what to do on a Macintosh platform.) I include a file called findJavac.bat in the download. After the .zip file is unzipped, just please type
findJavac
at the Dos prompt, (and push enter,) and all the instances of javac in the same drive as the Dos box will be found. Here is what it found for me:
C:\Program Files\Java\jdk1.6.0\bin\javac.exe
C:\Program Files\Java\jdk1.7.0\bin\javac.exe
As I write this, version 6 is stable and version 7 is in beta, so I wish to add version 6’s javac to the path. The trick is to form a new file called, say, path6.bat, by redirection. Just please type
findJavac > path6.bat
and open path6.bat in an editor. Inside the editor, we see
C:\Program Files\Java\jdk1.6.0\bin\javac.exe
C:\Program Files\Java\jdk1.7.0\bin\javac.exe
as I have said. Now please delete the second line and the mention of javac.exe, and put quotes around what remains of the first line:
"C:\Program Files\Java\jdk1.6.0\bin\"
and then please make it into a command to tell the computer to put it at the beginning of the path:
set path="C:\Program Files\Java\jdk1.6.0\bin\";%path%
and save the file and close the editor. Then typing
path6
at the Dos prompt will put the address of javac version 6 at the beginning of the path of that Dos box. It will stay there until that Dos box is closed. When the user comes back from lunch and a new Dos box is opened, just please type
path6
again, and javac version 6 will be put in the path again.
To top

Download, install, uninstall

The easiest way to download and install all these files is to download Print.zip into the folder where the macro-expansion is to occur and unzip it. Then the files will be ready to use. To uninstall, just delete the files.
To top

What deepToString can do and cannot do

The deepToString method can look inside arrays to find the things inside them. If one of those things is a Java collection, its contents are shown, because collections have toString methods. However, if one of the things inside a collection is an array, then deepToString cannot look inside that array. That is, a collection is not an array.

Also, deepToString is not found on Javas earlier than Java 5.
To top

The pri and pr and prin macros

The print macro causes both the formula and the value of the formula to be printed, for each argument. Printing the formula may be unnecessary. To print only the value of each argument, with commas between, use the pri macro instead of the print macro. Changing the earlier print example to a pri example we get
pri   eye   x

To print the values without the commas, use instead

pr   eye   x
This is sometimes handy when the line is to be read by a program instead of a human.

To print the names eye and x but no values or commas, use instead

prin   eye   x
That is, everything after the prin and its immediately following blanks and/or tabs will be printed at Java run time without changes. In order for this to happen correctly, the prin macro doubles each backslash.
To top

The deleteUnderscores macro

Nineteen digits together are hard to type in correctly, and just as hard to read back as a check. They need underscore separators, as in the Ruby and Nemerle languages. Our macro makes this possible:
deleteUnderscores long n=4_687_968_574_463_210_974L;
is changed to
long n=4687968574463210974L;
Strictly speaking, this is a micro, not a macro. That is, it makes things smaller instead of bigger.
To top

The doubleBackslashes macro

Books on Java first say the regular expressions of Java are just like those of Perl. Then the books change their minds and say that each backslash in a Perl pattern must be changed to a double backslash in a Java pattern. Who ought to double those backslashes? Not humans. Computers ought to do the job. For example, one might use
doubleBackslashes String yearPattern="\d\d\d\d";
to get
String yearPattern="\\d\\d\\d\\d";

To top

The milliseconds macro

In numerical analysis it is important to know how long a program takes to run, not counting the time it takes to load from the hard drive. The milliseconds macro helps with this. It looks, for example, like
milliseconds   a
and this changes into
long a=System.currentTimeMillis();
The reader is respectfully invited to click on Sincos.pri and on Sincos.java to see how the macro is used. It is important to divide (b-a) by 1e3, and not by 1000, so as not to lose the fractional part of the quotient.
To top

The swap macro

When writing programs to sort, to shuffle, and to get next permutation, we need to swap. In Fortan and Basic it is easy to write a swap subroutine. In Java it is, in general, impossible. Macros come to the rescue. For example, if we wish to swap a and b, we may write
swap   a   b  temporary
It will expand to
{ temporary=a; a=b; b=temporary; }
There must be exactly three arguments to the swap macro. The macro is not able to declare the arguments, so the programmer must arrange for them to be declared before the swap is used.
To top

Macros for functions

We Java programmers are accustomed to say that Java has no functions, only methods. We mean that methods are not first-class objects, that they cannot be passed through linkages as parameters. However, objects containing methods can indeed be passed. The most convenient way is to construct and instantiate local classes. The Java notation for such things is verbose and tricky, but macros shorten and simplify the notation.

For example, consider the file Midpoint.pri. It contains a method called midpoint for doing numerical approximations to definite integrals. The midpoint method returns a double. Its parameters are an Integrand called i, a double called a, another double called b, and an int called n. The doubles and ints are familiar. Integrand is an inner interface of the Midpoint class. The Integrand interface contains a double method called f, which has a double parameter called x. The Integrand interface is constructed by the myInterface macro:

myInterface   Integrand   double f(double x)
Here myInterface is the name of the macro, and it means we need to construct an inner interface in the top-level class that we are now in. The name of the inner interface is Integrand. Then there is a kind of signature, giving some information on the method. There is not any semicolon, because the macro will provide that here. The name of the method, f, is part of this signature. The name of the variable, x, is needed by the macro, so it too is part of the signature. Of course the user can change these names, only taking care to agree with herself.

An example of using the Integrand interface is the line

function   Integrand   multsin   return mult*sin(x);
It says to implement the Integrand interface, and instantiate, and put the object into a variable named multsin. The body of the f method is return mult*sin(x); with curly braces and other punctuation to be put on by the macro. That semicolon is part of the method body, not part of the macro syntax. Readers wishing to see the result can look at Midpoint.java. Then the result of plugging the multsin object and the doubles and the int into the midpoint method can be printed.

The function call is all on one line. Some method bodies take up too much space for one line, so there are two other macros to work them. They are beginFunction and endFunction. In the Midpoint.pri file they go around the fibonacci’s body. The beginFunction macro has only two arguments: the name of the abstract class to be extended, and the name of the variable to hold the object. The endFunction macro has no arguments.
To top

The stack

The beginFunction and endFunction macros are like parentheses. That is, they must nest correctly, and there must be equal numbers of each. The same goes for the for and next macros farther down in the present file. The same goes for the firstly and lastly macros after that. The macro system uses a stack to see if the nesting and equality rules are obeyed. Any diagnostic saying the word “stack” is talking about wrong nesting or failure of equality.
To top

The yourInterface macro

So far we have been considering only one top-level class, for example, Midpoint. Now it is necessary to think how to get to the Integrand inner interface from a different top-level class. The example is the UseMidpoint.pri file. It includes the line
yourInterface  Midpoint.Integrand   double f(double x)
The difference between yourInterface and myInterface is that yourInterface merely declares the interface and the “signature” of its method, but myInterface also constructs the interface there on the line of the output file. In UseMidpoint.pri we are referring to a different top-level class from our own, so we use yourInterface and give both parts of the name: the top-level class and the inner interface. We do have to give the signature, because there is no short, easy, dependable way for a macro-expander to see inside the other top-level class. The function call now looks a little different from how it looked in the Midpoint.pri file:
function   Midpoint.Integrand   sinc   return Math.sin(x)/x;
This is because we must again give both parts of the class name: top-level and inner. The same would apply if we used the beginFunction and endFunction macros. Similarly, the method names are preceded by class name and dot.
To top

What became of myClass and yourClass?

They are now respective synonyms of myInterface and yourInterface. There is no hurry about changing to the new forms, and all the user’s old .pri files will work as before. However, the .java files expanded from the old .pri files ought to be replaced by newly expanded .java files. For more information, please click on Changes.
To top

Composing two functions

So far methods have used functions only as parameters. Can a method return a function? Of course it can. The file Composition.pri shows a trivial example. First it defines the Real2Real interface:
myInterface   Real2Real   double f(double x)
This is for functions from the reals to the reals. Then the compose function takes two Real2Reals and composes them and returns the result as a Real2Real. The main method checks to see if this happened correctly.
To top

Implementing two or more interfaces

In the Java language, two different interfaces with the same signature are not the same thing. Sometimes they can do the same work, and sometimes they cannot. In the present section we see an example where they can.

Imagine that two different programmers were assigned to write different methods. The first programmer was to write a method to approximate the maximum of a function defined on a rectangle by picking points at random and taking maximum. The second programmer was to write a method to approximate the minimum of a function defined on a rectangle by picking points at random and taking minimum. In the real world, they would write different files and e-mail them in. However, to spare the reader’s nerves, I have put all their work in the same file. Also I have put in that same file a main method to call both methods. The file is called Max2.pri.

The reader sees at once that each programmer used a different interface, but the two interfaces have the same signature. (The signature to use was told to the programmers before they started.) That means that it is possible to implement both interfaces at the same time. We do this on each beginFunction and function line by putting the names of both interfaces in the same token with a comma between the names. The result of expansion of the macros is of course in the file Max2.java.

The reason that this works is that the functions were used only as parameters to the methods, but the methods did not return functions. The Java compiler will always catch a blunder of this kind, so the programmer need not worry about it. Just program what is desired, and if it is not permitted then javac will say so.

If there were three files instead of one, then the file with the main method would have to use yourInterface macros, and all the interface names in that file would have to have both top-level class and inner interface with a dot between, as I said above. Similarly, the method names would have to be prefixed with their top-level class names and a dot, as above.
To top

Two other files using functions

Functions are so much fun that I wrote two more numerical analysis files to use them. The first is GetRoot.pri. It contains a method called bisect which does the bisection algorithm for finding the x value where a continuous function crosses the horizontal axis. The inner interface containing the signature is called Continuous, and the user is on her/his honor to use only continuous functions. Actually, the last function in the file is discontinuous, so the algorithm fails.

The second file is HalfStep.pri. It contains a method called halfStep for solving systems of ordinary differential equations with initial conditions by the half-step algorithm. The inner interface containing the signature is called Derivative, and each Derivative function receives a double array of values, and computes from it a double array of derivatives at those values. I leave it to the user or to her students to write the Runge-Kutta algorithm in the same style. The signature need not change. It suffices to write a new method to compete against halfStep.
To top

Using a throws clause

Sometimes a function needs to throw an exception. The file Thrower.pri is an example. It includes the line
myInterface   TableWorthy   double f( double x ) throws Exception
which shows a signature including a throws clause. The TableWorthy type is needed by the printTable method. In the main method a function called t is built which is passed to printTable along with three numbers telling where to start, where to stop, and what the step is. The t function throws an exception if its argument is out of domain.
To top

The Metropolis algorithm: probability

The files in the previous sections are merely elementary numerical analysis, and they need only one signature each. In this section I present the Metropolis algorithm, which needs three interfaces, each with a different signature. Its file is Metropolis.pri. The algorithm itself is in the metropolis method. The Height interface is for un-normalized probability or un-normalized probability density. The Propose interface is for the symmetric proposal function. The Report interface is for reporting back to the main method and incrementing some totals and doing a little printing.

The main method defines a function h which is the standard univariate normal without its normalizing denominator. The function p makes a symmetric proposal using the centered uniform distribution. The function r increments some totals and, once in every million times, prints average and variance. If everything goes well, the average will approach zero and the variance will approach unity.

The file is copied from the ideas of Nicholas Metropolis, but he is not responsible for any errors I may have made. I have made no provision for tuning the algorithm or burning it in, but it seems to work anyway.
To top

The Metropolis algorithm: statistics

That previous section worked a probability problem. Actually, in our time the algorithm is used mostly for statistics, and indeed for Bayesian statistics. The LogMetro.pri file is meant to illustrate this. First of all, the letter x is replaced by the letter p, because the random walk is in parameter space, not in sample space. The myInterface Height double f(double[] x) line is replaced by the myInterface LogHeight double f(double[] p) line. This is because we will use logarithms of heights instead of the heights themselves, in order to avoid overflow and underflow. Then the metropolis method is replaced by the logMetro method. In the logMetro method, the calculation of ratio is different: we use the exponential of the difference of the logarithms of the two heights.

The LogMetro.pri file purports to work Darwin’s experiment on crossed and self of Zea mays by a Bayesian method, not by the frequentist method of Fisher. See pages 16ff of http://darwin-online.org.uk/content/frameset?itemID=F1249&viewtype=text&pageseq=414&keywords=zea%20mays for Darwin’s numbers and Galton’s comments. The x array in the main method contains the differences of the two plants in the same pot, following Fisher, not following Galton. The density model I use in the new method logDensity is exp( -abs(x-center)/scale )/(scale*2), which is not Gauss’s normal density. As Galton remarks, quoted by Darwin, the “law of error” seems not to apply here. Instead of making scale a parameter, I make the logarithm of scale a parameter. (This is a common practice.) The prior probability is uniform for the two parameters: center and logarithm of scale. The logHeight function merely adds up the logarithms of the heights for the x’s.

The propose function is much like that in the previous section, but now it works in two dimensions. The report function counts how many times the center was negative, and every million times around the big loop it prints the total number of times, the number of negatives, and their ratio: leftProb. When I ran the program, leftProb appeared to approach a number slightly smaller than .0014 . That is, if the algorithm and model and prior are appropriate to this problem, (and if I understood and programmed all this correctly,) then the probability that self makes bigger plants than crossed is slightly smaller than .0014, and the probability that crossed makes bigger plants than self is slightly larger than .9986 .

Users of the Metropolis algorithm are as always reminded that (1) the algorithm need not converge, (2) it might converge to a wrong value, and (3) even if it does converge to the right value, there is no way of knowing that this has happened.
To top

The ShadedContours program

This program was changed in four ways on 17 August 2007. Users who are downloading PrintMacroJ for the first time may skip to the next paragraph. (1) The way of removing the decoration is now the Esc key only. Other keys will no longer work. This is to make the use of the Alt and PrintScr keys easier. (2) The Esc key does not make a second window, but only removes (or restores) the decoration. (3) Clicking on the decoration to close a window will close only that window. Other windows will stay open. (4) When a window is opened for the first time, it takes up as much space on the monitor screen as the operating system will permit.

It appears that there are two kinds of contour-plotting programs. One kind plots functions, and the other kind plots matrices of numbers. ShadedContours.pri is the first kind. There is a main method at the bottom of its file to make a plot of the contours of Math.tan(x*y). The title of the plot is Tangent of Product. The function which calculates Math.tan(x*y) is named tangent. The x values lie between -5 and 5, and the y values lie between -5 and 5. The number of shadings between contours is 6.

When the program is started by means of the pri.bat file, a “decorated” window will open showing white pixels for very positive function values, nearly black pixels for very negative values, and shades of gray in between. Where white touches nearly black there is a discontinuity. The contours are the boundaries between the shadings, so they are not separately drawn. The window can be dragged and resized, and its contents can be copied to the clipboard by holding down the Alt key and pressing the Print Scr button. Then the clipboard can be pasted down into Microsoft Word, or some other high-quality program, to be printed. (The reader can guess that I use Microsoft Windows on my computer.) WordPad is not high quality for images.

Why is the window decorated? So that it can be dragged and resized and hidden and closed. Unfortunately, the decoration gets in the way of some of the contours. What we want is a way of removing the decoration. The way of removing it is to click the window with the mouse to make sure it has the focus, and then to push the Esc key on the keyboard. Then the decoration will be removed. (Pushing Esc again will decorate the window, and so on.) The Alt and Print Scr keys can be used either with or without the decoration, but without looks better. To end the program, just put the decoration on, if it is not on, and click on the “X” of the decoration to close the window.

Of course, the ShadedContours class will usually be instantiated from another file. An example is UseShadedContours.pri. This file plots two different windows, one for Math.sin(x*y) and one for Math.log(x*y). The latter window has 12 shades instead of only 6. There is a yourInterface declaration, and the inner interface ShadedContours.Altitude gets its full name. The two windows open with the same location and same size, so one must drag and resize to see both at the same time. Then they may be undecorated by the Esc key as before. The “X” close icon on the decoration of a window will close only that window, so two clicks are needed to end the program, one click on each decoration.

At first the contours for Math.sin(x*y) may look like those for Math.tan(x*y); the boundaries are from the same family of hyperbolas. However, the shading is different, and white and nearly black on the sine window can never touch each other. This is because the sine function is continuous. The contours for Math.log(x*y) are new. The second and fourth quadrants are dead black, even blacker than the nearly black mentioned above. This is to signify NaN, because logarithms of negative numbers are not real.

Now to explain how the ShadedContours program works. All the trickery is in the paint method. The double for loop for the variables eye and j looks at each pixel position in the window. The x is calculated from j and the y from eye. Then the altitude function is used on x and y to get z. If k is 1, then the z’s are collected in the alts array and a count kept of the NaN’s. Then the array is sorted, and when k is 2 the rank of z is found by binary search. The rank determines the shade of gray. That is to say, no calculus is used at all, and singularities and discontinuities are easily handled. (However, the z difference between the first and second contours is usually not the same as the z difference between the second and third contours, and so on.) Of course, this algorithm could not be used until computers came to their present speed and size. The problem of plotting contours is not solved; it is overpowered. The reader is respectfully invited to compare the present algorithm against its old-style calculus-using competitors, especially in the case of Math.tan(x*y) .
To top

The unclass.bat file

Using inner classes can make a lot of .class files, and one needs a simple way to get rid of them. A batch file named unclass.bat is provided for Windows users to use at the Dos prompt. It will delete all .class files in the current folder and in all its subfolders. Yes, this deletes Print.class. No, this will not cause trouble, because the pri.bat file always looks to see if Print.class exists, and recompiles it if necessary.

In fact, I do not provide a Print.class file, or any .class file, in the zip. Print.class is compiled the first time pri.bat is used.
To top

The AllPriUnJava.pri file

It is not only .class files which need to be deleted now and again. The .java files written by the pri.bat batch file become too numerous after a while. What we need is a way of deleting only these .java files but not the other .java files. A special program called AllPriUnJava.pri is furnished for this purpose. To use it type and enter these two lines at the Dos prompt:
set left=AllPriUnJava
pri
Then all the .java files in the current folder (except FileNames.java) which have .pri files to them in the current folder will be deleted. Yes, AllPriUnJava will even delete its own newly-built .java file.

The old name of this file was UnJava.pri, but then I saw that the old name was unclear in its meaning, so I changed it.
To top

The AllPri2Java.pri file

Sometimes deleting all those .java files turns out to have been a mistake. To get them all back, a program called AllPri2Java.pri is furnished. To use it type and enter these two lines at the Dos prompt:
set left=AllPri2Java
pri
Then all the .pri files in the current folder (except those whose .java files exist and are younger than their .pri files) will be macro-expanded to .java files. This does not apply to FileNames.pri.
To top

The PriUpdateJava.pri file

Nothing is more irritating than changing a library .pri file and forgetting to expand it to the new .java file. When a different file using this library is being expanded and compiled and loaded, the javac and java tools may not know that anything is wrong, so there may be no diagnostic. The PriUpdateJava.pri program is meant to help when this is suspected of happening. Just type and enter
set left=PriUpdateJava
pri
at the Dos prompt, and all the .java files in the current folder that are older than their corresponding .pri files will be replaced by newly expanded .java files. “All” means all except the FileName.java file. Of course, .java files having no .pri files will not be affected.
To top

The FileNames.pri file

The reader who has read the three sections above will have noticed the name of the FileNames class. Its source is in FileNames.pri. It contains an interface called Work which can be referred to by yourInterface, and a method called loopFileNames expecting to get an object of type Work. The method makes a list of the files in the current folder and presents them, one at a time, to the f method of that object. However, it never presents FileNames files, so as not to interfere with itself.
To top

Overloading operators for primitives and immutables

One of the fun Java homework assignments in computer science class is writing a “rational arithmetic” class. Once the student sees the trick of using the greatest common divisor method of the BigInteger class, it takes only about half an hour to implement add, subtract, multiply, and divide. Then the student tries to write a little algorithm in rational arithmetic, say Newton’s loop to solve an equation, and things get tedious. Java will not allow the programmer to overload operators, so the algorithm is hard to write and hard to read.

What is needed is a macro. I have written it and named it let to remind me of Basic. One may write, say,

let x = yy + zzz * wwww ^ vvvvv
and it will get changed to
x=add(yy,multiply(zzz,power(wwww,vvvvv)));
The reader will notice three things about the let call. Firstly, there are blanks around the variable names and operators. These are required to separate them. Secondly, the let call has no semicolon at the end, any more than the print call does, because they are both macros. Thirdly, the operators change into static method calls, not instance method calls. This is for generality, because sometimes we wish to use operator overload for primitives, and they cannot have instance methods. Also, we may wish to use a final class, and its instance methods may not suit our needs.

I have been assuming that the static methods are in the same class as the line containing the let call. If they are in a different class, say, RatioStatics, then we use

staticsClass RatioStatics
let x = yy + zzz * wwww ^ vvvvv
and the result is
x=RatioStatics.add(yy,RatioStatics.multiply(zzz,RatioStatics.power(wwww,vvvvv)));
As long as the computer does all this typing, I don’t care how tedious it is. The staticsClass call need occur only once in the file, earlier than the let calls to which it belongs. Also, it is legal to use more than one staticsClass call, changing to suit the let calls in different parts of the file.

Three other operators known to the let macro are ** and new and fresh. The ** operator is an exact synonym of the ^ operator, but it imitates Fortran instead of Basic. The new operator has the same meaning as in ordinary Java. The fresh operator means use a constructor. Here is an example of its use:

constructorsClass RatioStatics
let x = fresh 5,6
where 5,6 is written solid with no blanks. It will change to
x=new RatioStatics(5,6);
Here I have assumed that x was already declared. If it was not, we may use
constructorsClass RatioStatics
let RatioStatics x = fresh 5,6
and get
RatioStatics x=new RatioStatics(5,6);
because the let call may take modifiers and class names on the left hand side. The constructorsClass call need occur only once in the file, earlier than the let calls to which it belongs. Also, it is legal to use more than one constructorsClass call, changing to suit the let calls in different parts of the file.

Parentheses are permitted in the let call, and they have their usual meaning. Commas are permitted too, and they are useful for static method calls:

let int eye = RatioStatics.compareTo ( x / y , u - v )
Please remember about those blanks for the parentheses and commas.

Let me say a word about subscripts. The let macro does not know anything about subscripts. Nevertheless, they may be used, provided that they are written solid with no blanks. Here is an example, with extra-wide spacing:

let   x[i][j]   =   y[i]   +   z[j]
The tokens containing the subscripts look like variable names to the let macro, so the result is, assuming staticsClass is blank,
x[i][j]=add(y[i],z[j]);
just as one would hope.

The let macro can do not only the binary + and - operators but also the singulary + and - operators. The singulary operators are changed to plus and minus, respectively, but the binary operators are changed to add and subtract, respectively.

Also, the let macro can do the ternary operator and relational operators and boolean operators. A contrived example is

let DemoTernary x = ( y < z ) ? y + z : y * z
A contrived example file is DemoTernary.pri, and it is changed to DemoTernary.java. The allowed relations are < > <= >= == != and they change respectively to lt gt le ge eq ne. The allowed booleans are && || ^^ and they change respectively to && || ^. I know that there is no such thing as ^^ in Java, but I had already used ^ for a power symbol, as in Basic. I apologize to everybody. I have not furnished a ! operator for negation, and I apologize again. I have found out how to do negation, so now let has negation using the ! operator.

The let macro is meant for primitives and for immutable objects. It cannot do anything to mutable objects except instantiate them.
To top

RatioStatics

Here is the RatioStatics.java file. A file to use it is DemoRatioStatics.pri, which is expanded to DemoRatioStatics.java. The demo program is trying to find the square root of 5/6 by Newton’s loop. Rational arithmetic can be slow, but for theoretical math it is great fun.
To top

BigDecimalStatics

Here is the BigDecimalStatics.java file. A file to use it is DemoBigDecimalStatics.pri, which is expanded to DemoBigDecimalStatics.java. The reader will notice the line let BigDecimalStatics.mc = new MathContext(60). If that line were omitted, the default value of 50 digits would be used. Also, the reader will notice that the exponents of x are not marked fresh. This is because they are ints, not BigDecimals. The program is trying to solve the equation x5 + x + 12345 = 0 by Newton’s loop.
To top

DoubleStatics

Here is the DoubleStatics.java file. A file to use it is DemoDoubleStatics.pri, which is expanded to DemoDoubleStatics.java. The program attempts to solve the equation x5 + x + 1.23456789 = 0 by Newton’s loop. The let statements could be written in regular Java almost as easily, but the ^ operator for power would not be available. The reader will notice that the new and fresh key words are not used in this program, because the doubles are primitives.

The DoubleStatics.java file has methods for doubles but not any for ints. This means that ints will be promoted to doubles. Here is an example:

public class Junk
{

	public static void main(String[] args)
	{
	staticsClass DoubleStatics
	let double x = 2 / 3
	print x
	}

}
The printed value of x will be 0.6666666666666666, not zero. This is what Dartmouth Basic did in the old days, and what TrueBasic and JavaScript and Lua do now, but it may not be what the reader expected a Java program to do.
To top

Import static and the compPivMat package

It is little bit tedious to use the staticsClass macro, and only the most recent use affects the let. It would be easier and more general to use the import static statement of Java. Here is an example: DemoCompPivMat.pri. The compPivMat package has only one class in it, compPivMat\CompPivMat.pri. The class is a small collection of static methods to do arithmetic on matrices. The matrices are merely double[][] arrays. There are methods to do singulary plus, singulary minus, add, subtract, multiply, divide (on the right) and reverseDivide (on the left). The "\" sign is for reverseDivide. There is also a transpose method.

The package is merely a subdirectory. It is not a Java archive (.jar file,) so please do not change the classpath. The package does not yet contain a .class file, but when the user compiles a file referring to the package, say by typing pri at the Dos prompt, javac will write the .class file for the package without saying anything.

A user who wishes to change compPivMat\CompPivMat.pri should keep in mind that everything must be done from the parent directory, not in the package. For example, one might type at the Dos prompt

set left=compPivMat\CompPivMat
notepad %left%.pri
to open an editor. (I am thinking of Microsoft Windows here.) After making changes and saving the file, one can use the priOnly.bat macro. At the Dos prompt one types
priOnly
to macroexpand the .pri file to a .java file and call javac on the result. There will be no attempt to run. This is because there is no main method. If there is a main method, pri cannot run it. If by mistake the user uses the pri at the Dos prompt instead of the priOnly, the files will be correctly changed, but then there will be a frightening diagnostic which may be safely ignored.

I nearly forgot to say what DemoCompPivMat.pri does. It uses least squares to fit a polynomial of degree k-1 to some xData,yData points.
To top

Let and Dac

As the reader has probably guessed, Let is a tiny compiler. It is a top-down recursive syntactic recognizer without look-ahead or back-track. Its source is the Let.dac file. This is converted to the Let.java file by the Dac program, whose source is the Dac.java file. Dac is a tiny compiler-compiler. Dac stands for “dollar, altern, and catena.” The dollar control means “zero or more examples of.” (Back in the fifties this was an actual dollar sign.) The altern control is an alternation, that is, it is a list of things one of which must be true or the pattern fails. The catena is a concatenation of things, all of which must be true in order, or else the pattern fails. If the first thing succeeds but a later thing fails, the whole program quits with a diagnostic, because the program cannot back up. If the first thing fails, the pattern fails, and some other pattern can be tried. Pieces of Java written inside curly braces do not count as parts of the catena pattern. They are only semantic, usually. The Let compiler has a boolean called toggle. The controls and other parts of the program use this toggle to communicate with each other.
To top

Overloading operators for mutables

Using let on primitives is speedy, because the -server optimizer will see what is going on and speed the code up hard. Using let on other peoples’ final immutables, such as BigDecimal and BigInteger, will not slow them down much, because they are already slow. On the other hand, we user programmers write complex-valued arithmetic ourselves, starting with two double variables, one for real and the other for imaginary, and immutable objects will slow these down unconscionably.

The web has few examples of mutable complex-value arithmetic, but there are some, and they are unexpectedly speedy. I will say later in this file how speedy. Here is what a call of the mutate macro may look like:

mutate x := y + z * w
The reader sees the word mutate instead of let and the := operator instead of the = operator. This is to emphasize that x is not a new object. It is the same object as before, but its contents are changed. On the other hand, it is important not to mutate the variables y, z, and w. If constructorsClass is ComplexMutate then the line expands to look like
{ multiply(temporary0ComplexMutate,z,w); add(temporary1ComplexMutate,y,temporary0ComplexMutate); copy(x,temporary1ComplexMutate); }
The “temporary” variables hold the results of the multiply and add. Those temporary variables cannot construct themselves, so we use a macro called makeTemps to construct them. The call
makeTemps 10
will build ten of them, from temporary0ComplexMutate through temporary9ComplexMutate. They will end with the name and have the type defined by constructorsClass, and again I have assumed that it is ComplexMutate. If ten is too few, javac will complain, and the programmer may double to twenty, say. If ten is too many, the mistake is harmless.

Each method of a .pri file needs its own makeTemps calls, and they must come before the mutate calls which need them.
To top

ComplexMutate

The file of static methods is ComplexMutate.java. The reader can see that each static method is careful to mutate only the outward parameter, no other. I point out an oddity: the abs and taxi methods return both real and imaginary parts, but of course their imaginary parts are zero. Those two methods must do this because all the “temporaries” of a mutate call must have the same type.

A demo program is DemoComplexMutate.pri which becomes DemoComplexMutate.java. I have made a point of not using fresh inside the loop, because that would construct and destruct objects inside the loop, exactly what we wish to avoid. I do need many named variables to move the freshes out of the loop.

Now here is something new, not like the “demo” programs. It is SincosComplexMutate.pri and of course its .java file SincosComplexMutate.java. This is a particularly crude form of Euler’s algorithm to solve the sine and cosine ordinary differential equations starting from zero for the sine and one for the cosine and going around the loop a billion times. (American billion.) On my computer this Java program takes 15 seconds to run. For comparison, the corresponding program in Gnu C++, using the built-in _Complex double, and using the command-line modifiers for greatest speed, takes 14 seconds. A famous proprietary freeware C++ takes 15 seconds, the same as our Java program. Other freeware C++es seem to be slower.

The Euler algorithm was chosen to make the ComplexMutate class look speedy. Unfortunately, most useful programs in numerical analysis have subscripts, and Java programs having subscripts are slow. I have timed the matrix multiplication of complex-valued matrices, and a Java program using ComplexMutate is about 2.5 times as slow as the corresponding program in Gnu C++. (Thirty-two seconds for Java and thirteen seconds for Gnu C++, edge size 200, 100 repetitions.)
To top

Mutate and Dac

As the reader has probably guessed, Mutate is a tiny compiler. It is a top-down recursive syntactic recognizer without look-ahead or back-track. Its source is the Mutate.dac file. This is converted to the Mutate.java file by the Dac program, which I have mentioned earlier in this file.
To top

The for and next macros

The print and let macros resemble statements of the Basic language, so for old times’ sake and readability I add macros to imitate Basic’s for and next statements. The for declares its controlled variable to be an int so that it can be used in Java’s subscripts. Optionally, a step may be defined. Both kinds of fors appear in Eratosthenes.pri. It is changed to Eratosthenes.java.

Now we come to the fun part. The macro-expander checks to make sure that the controlled variable of the for is the variable of the matching next. This is a feature of Basic that other computer languages don’t have, and I find it helps in reading a file with big nests of loops.

I emphasize that the starting and stopping values of the controlled variable and the value of the step must each be a single token having no blanks inside. As usual, the values and keywords and = sign must be separated by blanks. Failure to keep to these rules will prevent the macro-expander from seeing that these statements are the Basic for, and javac will say something unkind.

Now the bad news. The macro-expander cannot check that the step value is an integer. If it has a fractional part, the loop will work wrong. The javac compiler will know that a mistake has been made, but it won’t tell.

The macro system uses its stack to check that the for and its next are using the same controlled variable, and that different for loops nested one inside another are using different controlled variables. The latter check is found also in the better class of Basics and in Fortran’s do loops.
To top

The firstly and lastly macros

The “endFunction” macro marks the end of what the “beginFunction” macro began, and the “next” macro marks the end of what the “for” macro began, but some of the keywords of java have effect for many lines and then finally are closed with a right curly brace that looks like all the other right curly braces. This is hard on a human programmer. We humans need marks at the end to match marks at the beginning. I have accordingly invented the “firstly” and “lastly” macros. For example, instead of “public class HyperbolaTable” one may use “firstly public class HyperbolaTable,” and then one ought to write “lastly public class HyperbolaTable” on the line following the last closing curly brace of the body of that class.

This may make more sense if the reader will be kind enough to click on HyperbolaTable.pri. I do something similar to the main method and to a multi-line if statement. The token “firstly” is erased from its line, but the rest of the tokens on that line remain. The token “lastly” and all the other tokens on its line are erased, so the line becomes empty. To see this, the reader is respectfully invited to click on HyperbolaTable.java.

If the tokens following a “firstly” do not match the tokens following its “lastly,” then there will be a diagnostic, and the macro-expansion will stop.

The firstly and lastly use the same macro-time stack that was mentioned above.
To top

Lonely curly braces and lonelyCurly

Let us define a lonely curly brace to mean a curly brace all alone on its line, except for white-space. It is time to include the lonely curly braces in the macro-time stack. The way is to begin the file with the word lonelyCurly. This word tells the macro system to watch for lonely curly braces and stack them and check them for correct nesting, as it does with the other nesting macros. Here is a nonfictional example to click on: CheckBook.pri. It is changed to CheckBook.java.
To top

The go and stop macros

Java programs are too big, especially the little Java programs. Suppose that I have forgotten the exponential of 3, and that I brought the wrong slide rule to work. Do I really need to declare a class and a main method and put on the Math. prefix? No longer. The reader is respectfully invited to click on Junk.pri to see how little I need to type. The resulting Java file after macro-expansion is Junk.java, and I am glad that I did not have to type that on the keyboard. Anyway, go Junk does a static import of java.lang.Math.* and declares the Junk class and the main method, and stop puts on the last two closing curly braces.
To top

The enforce and forbid macros

These are meant to replace the “assert” statement of Java. They are shorter to type, and they do not require a special command-line modifier. That is, they are for the applications programmer, not the system programmer. For examples of enforce one may look at GetAngleBetween.pri. Please notice the line reading
enforce bigX!=0 bigY!=0
This is two enforces on the same line. An enforce throws a new Error if its boolean expression is false.

The opposite of enforce is forbid. If the boolean expression in a forbid is true, then the forbid throws a new Error. Both the enforce and the forbid give complete details when they throw. That is, the “second expression” of the “assert” is not necessary (or possible) with enforce and forbid.
To top

The define and unDefine macros

Now it occurs to me (and perhaps to the reader) that the mutate macro may be an example of “too much.” Back in the days of the “m4” substitution macro system people got by with less. I imitate the use of m4 a little bit in a file called SincosComplexMacro.pri. It expands to SincosComplexMacro.java. The reader sees that the former file has three uses of the define macro, and it defines substitution macros called add, subtract, and multiply. Each of these substitution macros takes three arguments called $1, $2 and $3. These are used later in the for loop:
		for( int j=0;j<n;j++ )
		{
		multiply Temp C H
		add S S Temp
		multiply Temp S H
		subtract C C Temp
		}
The four lines inside the loop say: Temp is C times H, S is S plus Temp, Temp is S times H, and C is C minus Temp. This arithmetic is “complex.” My notation is different from that of m4, but mine takes less typing. The Temp and C and H of the first multiply are respectively substituted for its $1 and $2 and $3. Similarly for the other lines of the for loop.

The unDefine macro erases the definition made by the define. For example,

unDefine subtract
could be used after the end of the for loop to erase the subtract and prepare for the defineing of a new kind of subtract.
To top

The keyValue and unKeyValue macros

The reader sees that in the previous section new substitution macros were defined by the use of the define. These took arguments when they were used, but only one call of a new macro could be used to a line, and the name of the new macro had to be the left-most token.

In the present section we do it the other way. We define a substitution macro by the use of the keyValue. The new macro cannot take any arguments, but it may occur any number of times on a line. Wherever it occurs, there must be (invisible) word boundaries on its immediate left and right. For an example I have written SincosComplexEuler9New.pri. It needs to refer to itself 21 times. The name of the class is 22 letters long. That is too much typing on the keyboard. I define a key called melvin to have the value SincosComplexEuler9New as follows:

keyValue melvin SincosComplexEuler9New
Then I just type melvin instead of that long 22 letter class name, wherever I need that class name. The result of the substitution is SincosComplexEuler9New.java.

The unKeyValue erases the definition made by keyValue. It would look like

unKeyValue melvin

Now I need to give a warning to the reader. When a line of a .pri file is read, PrintMacroJ replaces all that line’s keys by their respective values before it does anything else to that line. Then it looks at the left-most token to see if anything else needs to be done. This is an exception to the rule that macros do not interfere with other macros, and I did it on purpose.
To top

The cross and dot and dyad operators

There are too few multiplication operators. There are (at least) three different ways to multiply two vectors (small v in vectors) together. They are the cross, the dot, and the dyad. We cannot just use the asterisk, because we often need two or three meanings in the same program, and the signatures are just the same for each operator. The solution of the problem is to spell out the names in English. An example program is UseCrossDotDyad.pri, and its translation into Java is UseCrossDotDyad.java. That is, I have added three reserved words to the “let” command. In “let” these three words can no longer be used as names of variables unless they are touching non-whitespace characters. Other commands besides “let” are not affected.

My example program has static methods to define the three new operators, but the reader or user is always free to change these or to supplement them with other static methods having other signatures. (Complex[]? Rational[]?)

I emphasize that the three new operators have just the same precedence and associativity as the asterisk operator. This may lead to confusion. It is legal to write

let a = b cross c dot d
because the result of b cross c is a vector, and that can be dotted with d. However, if the user wishes to write the dot on the left and the cross on the right then it is necessary to write
let a = b dot ( c cross d )
Dropping off the parentheses will cause javac to print a diagnostic, because a scalar cannot be crossed with a vector.

I am not sure if my dyad method is correct. It does not check to make sure that the sizes of the two vectors are equal. Users desiring the check are respectfully invited to uncomment the enforce command.
To top

The setq and dotimes and right-paren macros

These are joke macros, but they actually work. They allow the programmer to write S-expressions, looking a little like Lisp. Actually, these are not Lisp at all. They are merely changed into M-expressions, using round parentheses instead of square brackets.

The setq is special. It changes to a Java assignment statement with equal-sign and semicolon. For example,

( setq sNew ( add s ( multiply c h ) ) )
will be changed to
sNew=add(s,multiply(c,h));

Also the dotimes is special. It becomes a Java for loop. The tokens must be a left paren, the word dotimes, another left paren, a token for the controlled variable of the loop, another token for the number of iterations, and a right paren. You are correct: the parens do not balance. For example,

( dotimes ( j n )
changes to
for(int j=0;j<n;j++){

A right round parenthesis all alone on a line is changed to a right curly brace. That is, the end of the dotimes loop is changed to the end of the for loop. This change occurs only if a dotimes loop starting on a previous line is still unrequited by its final right parenthesis. Nested dotimes loops are permitted. However, these joke macros do not make use of the macro-time stack mentioned above.

The other operators, here add and multiply, are assumed to be names of static methods. An example file is SincosEulerSetq.pri. It is changed to SincosEulerSetq.java. The reader is respectfully reminded that the white-space separating the parentheses and other tokens is obligatory here.

The resulting Java program runs at full Java speed, perhaps because the JIT compiler moves the static methods inline. The Java program is more than forty-two times as speedy as my corresponding Lisp program, sincosEulerSetq.txt, using the speediest Lisp system that I know about, Steel Bank Common Lisp. (Yes, I know the suffix ought to be lisp instead of txt, but most browsers don’t know what to do with a lisp file.) However, I am no Lisp programmer, so it may be that my Lisp program is poorly written, or that I have used Steel Bank incorrectly, or that there is a speedier Lisp. I respectfully invite correction from people who know better than I.
To top

Changes

On 1 August 2007 I corrected a big bug in the PrintMacroJ system. Users who downloaded PrintMacroJ only after that date need not worry about the bug. For users who last downloaded it on or before that date, it is necessary to delete some of the user’s old .java files and build them again. Here is how to do it in Microsoft Windows. First please make sure that javac is in the path. Then please select and copy and paste the following script:
set left=Update
pri
unclass
Then please push enter. In the current folder, the old .java files expanded from .pri files will be replaced by expanding those .pri files. (But .java files having no .pri files will be untouched.) Linux and Unix users will know what changes to make to this script. I do not know what Macintosh users ought to do.
To top

License, revision date, and e-mail address

The present file and all the other files in the present collection are in the public domain. (Java™ is of course the property of Sun.) The date of this revision is 25 February 2010. Comments both constructive and destructive come to me, Harold Kaplan,
       at        dot
smtw2gh  toadmail   com
For other links to Harold Kaplan’s programs, click on programming.htm.

For many more links for languages connected with Java, click on http://www.is-research.de/info/vmlanguages/.

To top