The features explained in this appendix are very helpful if you need to rerun existing scenarios for training or demonstration purposes, or in the event that you run into a bug in the program. However, for day-to-day use of the program, you can ignore them.
Complex programs such as the Rhino Retirement Analyzer are subject to what is colloquially referred to as “software rot”.63 Of course software does not actually rot or decay; if you run the same program under the same conditions, assuming it is a deterministic program that doesn’t make use of random numbers, you should always get the same results.
However, it is very unusual for a complex program to remain the same for any extended period of time, especially a program that employs tax calculations, which are subject to change at the whim of Congress as well as statutory changes such as tax bracket adjustments for inflation that cannot be known in advance.
Another reason to make changes in a program that might change the results is to add features to that program, which can happen hundreds or thousands of times during the lifespan of a complex program.
And of course every complex program will have bugs that will need to be fixed. Fixing one bug can introduce another one. Even if this doesn’t happen, any change to the algorithm may affect the results, so that the program now produces a different answer for the same inputs. Some of these changes are intended, but unintentional or unexpected changes may also result from a seemingly “safe” change.
As a result, a wise programmer will provide a way to run “regression tests” on such a program. Regression tests are tests intended to ensure that changes made to a program do not result in unexpected changes in the program’s output.
While it would, in theory, be possible to run regression tests via a GUI, doing so is infeasible for any significant amount of testing. The effort required to run even one test via the GUI is significant, and errors will inevitably creep into the testing effort itself. Since dozens or hundreds of tests will be required to have any reasonable chance of catching most errors introduced into a program as complex as this one, a way of running tests without user interaction is required. This means that we need a scripting language that can exercise the program automatically, and that can be invoked from the command line, generally via a batch file.
Once you have such a scripting language, it can be used for other purposes, such as reproducing bugs (often the hardest part of debugging) and for training, via a visual replay operation that shows the steps that the program goes through during its operation. The Rhino scripting language supports both of these additional applications as well as the batch mode of operation, as we will see later.
By far the most common use of the Rhino scripting language is to initialize the program with data that was previously saved, for which we use the rra
file type.
Let’s look at an example of how that works from the command line.
The simplest command-line example that uses the scripting language is to provide only the name of a script file as the argument. (See Figure C.1)
If you run this command, the resulting Rhino GUI window will look like Figure C.2.64
As you may have noticed, the program takes a few seconds to get to the final state you see in Figure C.2. What is it doing during that time?
It is initializing variables based on the JaneAndJimSmith023.rra
script file, then executing commands in that script file. Figure C.3 shows that entire script file. We’ll go over it in pieces as shown in subsequent figures.
There are three parts of an rra
script file: the file header, the variable assignment section, and the function execution section. Let’s start the analysis with the file header, as shown in Figure C.4.
The first line of the file header, in this case 1024
, tells Rhino the “file version” of this file. This file version number is modified whenever there is a change in the file layout that the program has to take account of when decoding the file contents. This prevents the program from being confused by an unexpected difference in the file layout, so that backward compatibility to earlier file layouts can be maintained to the greatest feasible extent. When there are incompatibilities, this version number allows the program to diagnose and report them in a reasonable manner rather than by simply being unable to read the file.
Now that the program knows the file version, it can decode a more specific set of scripting commands, so each line in the rest of the file has a specific layout. With file versions 1023
and 1024
, the file versions supported as of this writing, each scripting command has the following format:
The second line of the file header, in this case F0,FileType,rra
, is a “file type” command, as indicated by the command type letter F
. The number, 0
in this case, is ignored for this command type. The command name argument is FileType
, which is redundant in this case because the command type letter F
indicates the same thing. It tells the program what type of script file this is, which can affect the detailed file decoding.67 In this case, the file type is rra
, short for “Rhino Retirement Analyzer file”.
The third line of the file header, in this case R0,RevisionNumber,2158
, indicates the exact revision number of the Rhino Retirement Analyzer program that recorded this script file. This can be very useful to a developer who is trying to reproduce a bug or other result of running the program, because that information can be used by the developer to recreate an equivalent version of the executable program at any time in the future.
As we have already seen, there are quite a few variable assignments in an rra
script file. We will go over an example of each type of assignment rather than explaining every assignment in detail here.68 Let’s start with the assignment for AssetNominalReturn
, shown in Figure C.5.
This assignment command, like all assignment commands, starts with the command letter A
. As indicated previously, the 0
following the command letter is ignored when loading an rra
file. After the separating comma, we have the name of the variable, in this case AssetNominalReturn
, then another separating comma, and finally the value to be assigned to the variable, namely 7.000000
.69
So the effect of this variable assignment command is to set the value for AssetNominalReturn
to 7.000000
. Let’s look at the GUI representation of this value to check that it has been assigned the correct value. (See Figure C.6)
You may notice that the value in the file has 6 zeroes after the decimal place, whereas the value in the GUI has only one. This is because the GUI representation of floating point numbers is controlled by formatting in the program. In the case of the variables representing our assumptions for returns and inflation, there wouldn’t be much point in specifying a highly precise number, given that we would be lucky to get the first digit right.
The next line we will examine, ExpectedExpenseAmounts,10000, 30000,0,0,0,0,0,0,0,0,
is an assignment to an integer vector called ExpectedExpenseAmounts
. This variable corresponds to the amounts on the second line of the “Expected Additional Expenses” tab, as shown in Figure C.7.
Next we have an assignment to a Boolean variable called InflateExpectedExpenses: A0,InflateExpectedExpenses,T
. This corresponds to the checkbox in the GUI shown in Figure C.8.
Values for this type of variable can be either T
or F
, for what I hope are obvious reasons.
The next line we will look at is A0,SelfCalculatedInsurance, 1434,20,450000,Wed May 31 2017
. This variable, SelfCalculated Insurance
, represents an insurance policy, as follows:
1434
= the yearly premium
20
= the term of the policy, in years
450000
= the face amount of the policy
Wed May 31 2017
= the starting effective date of the policy.
The GUI representation of this variable is as shown in Figure C.9.
Next we have A0,Self_Cash,530000 which represents the amount of cash that the first client has in his or her portfolio. This is an integer variable, as indicated by the lack of a decimal point in the value. Figure C.10 shows the GUI representation of this variable.
The last variable assignment we will look at is A0,Self_DOB,Mon Jun 1 1959
, which represents a date variable corresponding to the date of birth of the first client.70 Figure C.11 shows how that variable is represented in the GUI.
The last portion of an rra
file is the function execution portion. This portion is the same in all rra
files in currently supported file formats. It consists of the lines
These lines cause the execution of functions in the program. The first of these lines, S0,Recalculate,
executes the same operation as the Calculate
button in the GUI, namely to update the calculation results according to the current variable values. The second of these lines, S0,ExecuteBest MethodCalculation,
causes the GUI to display the results of whatever withdrawal strategy and insurance selection produces the best result. This is equivalent to clicking the “Best” button shown in Figure C.12.
There are a number of other options available from the command line, which are detailed in the online documentation for the program. However, we can cover the most commonly used options used in testing here. These are the BatchProcessingMode
option and the SaveCSVFile
option, both of which are Boolean flag variables.
As an example, let’s use the following command line, which should be all on one line, but is broken up to fit on this page:
1.BatchProcessingMode
This option is set to F
by default, which means that the program will present the GUI for user interaction. Setting it to T
tells the program to load and execute the script file without showing the GUI.
Since our sample command line invocation includes the argument BatchProcessingMode,T,
the program will load and execute the script file, then exit without showing the GUI.
2.SaveCSVFile
This option is used in conjunction with the BatchProcessingMode
option, and is also set to F
by default. This means that when the program exits after loading and executing the script file, it will not produce the .csv output file. The .csv output file is generally used to verify that the program is still producing the same output as it did previously. Setting this variable to T
tells the program to save the .csv file with a name corresponding to the script file’s name.
Since our sample command line invocation includes SaveCSVFile,T,
after the end of execution of the script file the program will save the .csv file bookJaneAndJimSmith023.csv
.
So, the net effect of executing that command line invocation of Rhino will be to load and execute the script file called bookJaneAnd JimSmith023.rra
without showing the GUI, then saving the output file called bookJaneAndJimSmith023.csv.
The other type of scripting file used with the Rhino Retirement Analyzer is a recording of a run of the program, for later replay.
Figure C.13 shows several portions of an rrr
file called timingtest.rrr
, recorded during the self-test that the program runs every time it starts up.
Let’s start with the header, which, as before, consists of the first three lines of the file.
As before, the file version number is 1024, which is an arbitrary number assigned by the program to the specific layout of this file. The program uses this first line to determine whether it knows how to process this particular version of this type of file.
The second line, F0,FileType,rrr,
tells the program the type of this file. This file is an rrr
file, which is a Rhino Retirement Analyzer ‘recording and replay’ file.
The third line specifies the revision number of the program that recorded it, to allow that revision of the program to be recreated for later debugging and analysis if a problem should be detected.
The remainder of the file consists mostly of a number of variable assignment commands just like the ones in the .rra file with function commands interspersed where they occurred during the run of the program. The first of these function commands is
This tells the program to update the year numbers displayed on the screen so that they start with the simulation starting year (2017 in this case).
Another type of command is the M
command, which indicates that we are modifying the same variable as we did in the previous command. An example of such a sequence is: 71
So the format of the .rrr file is quite similar to the .rra format. Why do we need the .rrr file type?
There are several uses for this file type: