JOSS



JOSS (acronym for JOHNNIAC Open Shop System) was one of the first interactive, time-sharing programming languages. It pioneered many features that would become common in languages from the 1960s into the 1980s, including use of line numbers as both editing instructions and targets for branches, statements predicated by boolean decisions, and a built-in source-code editor that can perform instructions in direct or immediate mode, what they termed a conversational user interface.

JOSS was initially implemented on the JOHNNIAC machine at RAND Corporation and put online in 1963. It proved very popular, and the users quickly bogged the machine down. By 1964, a replacement was sought with higher performance. JOHNNIAC was retired in 1966 and replaced by a PDP-6, which ultimately grew to support hundreds of computer terminals based on the IBM Selectric. The terminals used green ink for user input and black for the computer's response. Any command that was not understood elicited the response Eh?.

The system was highly influential, spawning a variety of ports and offshoots. Some remained similar to the original, like TELCOMP and STRINGCOMP, CAL, CITRAN, ISIS, PIL/I, JEAN (ICT 1900 series), Algebraic Interpretive Dialogue (AID, on PDP-10). Others, such as FOCAL and MUMPS, developed in distinctive directions. JOSS also bears a strong resemblance to the BASIC interpreters found on microcomputers in the 1980s, differing mainly in syntax details.

Initial idea
In 1959, Willis Ware wrote a RAND memo on the topic of computing in which he stated future computers would have "a multiplicity of personal input-output stations, so that many people can interact with the machine at the same time." The memo gained the interest of the US Air Force, Rand's primary sponsors, and in 1960, they formed the Information Processor Project to explore this concept, what would soon be known as time-sharing. The project was not specifically about time-sharing, but aimed to improve human-computer interaction overall. The idea at the time was that constant interaction between the user and the computer in a back-and-forth manner would make such interactions more natural. As JOSS director Keith Uncapher later put it:

"There were two perceptions that I think drove the experiment. One was, from at least 1950, when I joined Rand, there was always a focus in the computer science part of Rand toward smooth user interaction. It was just built into us. We learned it from Gunning. ... all we thought about. The other was, seeing the mathematicians struggling with Marchant calculators, not being able to use JOHNNIAC in its raw form. It was just too hard. They had to learn to be programmers. It was just a frustrating experience for them. We wanted something that would look to them as being a natural way of thinking about an aid to the solution of their problems without very much training, and without any perception of becoming a programmer, because that would have kept them away."

A formal proposal to develop what became JOSS on the JOHNNIAC computer was accepted in March 1961.

JOSS-1
JOSS was implemented almost entirely by J. Clifford Shaw, a mathematician who worked in Rand's growing computing division. It was written in a symbolic assembly language called EasyFox (E and F in the US military's then phonetic alphabet), also developed by Shaw.

The JOSS system was brought up formally for the first time in May 1963, supporting five consoles, one in the machine room and another four in offices around the building. The early consoles were based in the IBM Model 868 Transmitting Typewriter, as the Selectric had not yet been introduced to market when development began. The first schedule was published on 17 June, with JOSS running for three hours from 9am to 12 every day. It was declared fully operational on eight terminals in January 1964. The final version was deployed in January 1965.

By this time the JOHNNIAC was already over a decade old, and its tube-based logic was never highly reliable to begin with. Even when it was working well, the system became so popular it quickly bogged down. Users were enthusiastic, one stated:

"People adjust their lives to fit around JOSS… No use coming into RAND before 10:00 am when JOSS arrives, in fact noon or after 5:00 pm is a better time, JOSS is less busy. When JOSS starts typing answers, the titillating pleasure is equaled only by the ensuing anguish when JOSS breaks off into jibberish [sic] or goes away commending your code to oblivion. We can hardly live with JOSS, but we can’t live without it."

Another put it more succinctly:

"It's better than beer — we're hooked."

JOSS-2 switchover
In May 1964, the decision was made to look for a new machine to replace the JOHNNIAC and dedicate it entirely to running an expanded version of JOSS. The machine would also have to support new terminals made to Rand's specifications, and be delivered by 31 October 1965.

A total of nine bids were received for the new machine. Digital Equipment Corporation (DEC) won the contest with their new PDP-6 system, and Air Force funding was released for the purchase. DEC also agreed to build thirty terminals based on the IBM Selectric typewriter modified with a special mechanism to advance to the next page in a fan-fold paper feed. Several other portions of the overall system were delivered from other companies.

The PDP-6 arrived in late July 1965, and was initially tested using Teletype Model 33's as terminals. The new version of the code was developed by Charles L. Baker, Joseph W. Smith, Irwin D. Greenwald, and G. Edward Bryan. The system was first declared operational in October, although this included six hours of scheduled maintenance per week. The first prototype terminal arrived in November. In December, a terminal in Las Vegas was connected to the machine remotely for the first time. In February 1966, this was sent to McClellan Air Force Base, followed by one in August to the Air Force Academy and two in September to ARPA and an Air Force office in the Pentagon. The first permanent offsite teletype connection for a Teletype Model 35 was installed at the Langley Air Force Base in February 1967.

With the new machine up and running, JOHNNIAC was taken offline on 11 February 1966, and officially retired on 18 February. Its last running program was written in JOSS and counted down seconds until it would be turned off. The machine was sent to the Los Angeles County Museum, and eventually ended up at the Computer History Museum outside San Francisco. Having been replaced by the JOSS-2 system, the original was retroactively known as JOSS-1.

JOSS-2 use
By the end of 1966 the new JOSS-2 system was fully functional and turned over to JOSS use 24/7. The new machine offered about 30 times the computational speed, five times the storage space per user, and many new features in the language itself. The new platform could ultimately support up to 100 terminals in simultaneous use. The Air Force remained the owner of the system, with Rand and others operating as consultants. CPU time was billed out to external users at a rate of about $1 per minute, although that was only during the actual execution, time spent typing and printing was free.

By 1970, there were between 500 and 600 users at Rand and various Air Force sites across the country. Many of these were occasional users, precisely what the system had been intended for. To support them, the custom terminals were equipped with special "JOSS plugs" so they could be wheeled from office to office and plugged into custom outlets. Two-hundred of the plugs were installed around Rand, and the terminal chassis was designed to be narrow enough to fit through doors while still leaving room for a coffee on one side. Toggling the power switch on the terminal caused it to connect at the new location.

The custom terminals had been designed for JOSS as the engineers felt that the Model 33's "telecommunications functions are a mystery to the untrained person" and would be too confusing for the occasional users to bother learning. In practice, the Selectric-based mechanisms proved too fragile for the constant use they saw and were frequently being repaired in the field by IBM servicemen. In 1970, a full third of the terminals were completely rebuilt, and the output from the computer slowed to improve reliability. The Air Force, by this time, had decided to use the Model 35 instead, as it was both readily available and much less expensive.

Uses were enthusiastic and to serve them, Rand began publishing The JOSS Newsletter, edited by Shirley Marks. Ultimately 44 issues were published between November 1967 and June 1971.

JOSS-3
In the early 1970s, programmers at one of IBM's west coast facilities built a JOSS-3 for the IBM 370/158 running OS/360. Little information about this system exists, with the exception that it was on this machine that JOSS finally retired. According to a note in a historical overview, Rand was hesitant to allow IBM to use the JOSS name, and as a result "the IBM version was never widely used."

Implementation


JOSS-II on the PDP-6 was divided into two parts, matching the internal memory layout of the machine. The machine was equipped with two banks of core memory, with 16k 36-bit words in each bank. The JOSS system itself, which included the operating system, user and file management code, terminal handler and the interpreter, used up much of the first of these banks. The second bank was used for user programs. Although this was a relatively large amount of memory for the era, the system was so heavily used that the 16k word user store was not enough, and it was backed up with a magnetic drum for paging support. The drum was driven by external hardware and did not require attention from the main processor.

In order to support multiple user programs, the PDP-6 hardware was modified to examine bit-20 of any address reference. If this bit was set, the address was in "user space" and was modified so that address zero pointed to the base address of that user. In this way, user programs could be moved about in memory without causing problems for the system, and the operating system could switch from user to user simply by changing a single internal register.

Permanent storage was provided by a Storage Products hard drive with 5.7 million words of storage. Like the drum, the actual input/output to and from the drum was handled externally, although in this case the movement was triggered by user actions to load and store their programs. An IBM-compatible tape drive was used to move data to and from the drive as needed, an operation that was also independent of the CPU. Two DECtape units were also available and worked in the same fashion as the IBM drive.

Terminals were handled through a custom "concentrator" that consisted of a mechanical Strowger switch that could connect any of the 300 to 400 possible terminal plugs to any of 40 outputs. A further eight lines were dedicated to Teletype Model 33 inputs, as opposed to the JOSS-style Selectrics. Those 48 lines were then connected to an electronic multiplexer connected to the CPU. The multiplexer was interrupt driven, meaning idle terminals did not use up any cycles.

The custom JOSS terminals were built by DEC. These consisted of a Selectric mechanism built into a custom chassis containing the communications system, power supply, and other components. A custom font ball was used to provide basic mathematical symbols like ≠ so two-character combinations like <> did not have to be used. The communications system was based on a 6-bit character code in an 8-bit packet with start and stop bits. The lines were driven at 120 bit/s to match the maximum 15 character per second speed of the Selectric mechanism. Shift-in and shift-out codes were used to move the ribbon from green to black and back. These codes were also noticed by the communications system and changed lights on the front panel to indicate whether the computer or user had control of the terminal at that moment.

Direct and indirect mode
JOSS introduced the idea of a single command line editor that worked both as an interactive language and a program editor. Commands that were typed without a line number were executed immediately, in what JOSS referred to as "direct mode". If the same line was prefixed with a line number, it was instead copied into the program code storage area, which JOSS called "indirect mode". New lines were added to the program if the line number was unique, replaced extant lines with the same number, or removed from the program if an extant line number was typed in with no code following it.

In contrast to most BASICs, JOSS saved the entire user input to files, not just the program code. When loaded, JOSS essentially typed the lines back in. This meant that program files could contain both program statements and direct mode instructions. For instance, it was common to see programs that listed the statement lines and then have the file end with Go. to immediately run the program as soon as it completed loading. There were some features that could only be used in direct mode, like Let and Form, which were input without line numbers but still returned when the program was loaded.

Direct and indirect instructions could be mixed freely in a workspace. This allowed comments to be inserted in source code by adding direct-mode lines beginning with *, or by placing one at the end of a line of code and then adding a comment after it. Blank lines were also ignored, allowing the program to be broken up for clarity.

Program statements
Every line in a JOSS program must start with a line number. Line numbers are fixed-point numbers consisting of two two-digit integers separated by a period. As in BASIC, line numbers are used both as labels to target from To and Do statements, and to support editing. Entering a line of code with a new line number inserts it into a program, while entering one with an extant line number replaces the prior version or deletes it if it is empty.

The portion of the line number to the left of the period is termed the page or part, while the portion to the right is termed the line. Thus the line number 10.12 refers to page 10, line 12. Branches can target either a page, or a line within a page. When the later format is used, the combined page and line is termed a step.

Pages are used to define subroutines, which return when the next line is on a different page. For instance, if a subroutine for calculating the square root of a number is in page 3, one might have three lines of code 3.1, 3.2 and 3.3, and it would be called using Do part 3. The code would return to the statement after the Do when it reaches the next line on a different page, for instance, 4.1. No need exists for the equivalent of a RETURN at the end, although if an early return is required, Done accomplishes this.

Every line must start with a command keyword following the line number. No concept of a default command exists as is the case in BASIC with its optional LET statement. Multiple statements can be placed on one line, separated by colons or semicolons. Every line must end with a period.

Loops and conditions
JOSS uses a suffix notation to indicate conditional evaluation, "do this if this is true", in contrast to most languages which place the condition in front in prefix notation, "if this is true, do this". Unlike FORTRAN or FOCAL, any statement can be conditionally evaluated in this fashion. For example, to print a string only if a condition is met, one can combine the if with a Type:

1.1 Type "Hello, World!" if X=5.

JOSS supported six infix comparisons, =, ≠, ≥, ≤, >, <, and boolean operators or, and, and not.

Loops were handled in a similar fashion, using the For command and a somewhat obscure format for specifying the loop bounds and step value, start(step)end. For instance, to step from 1 to 10 by 2, the format is 1(2)10. Like If, For could be applied to any other statement:

1.2 Type "Hello, Wikipedia!" for i=1(2)10.

Note that the for applies only to a single statement; if one wants to run multiple statements in a loop, they would be separated to another part and called using do:

1.3 Do part 5 for i=1(1)100. 5.1 Type "Hello, Wikipedia!". 5.2 Type "This is JOSS.".

As in BASIC, any of the inputs to the for loop could be constants, variables or other expressions.

As these sorts of ranges could be applied to any line of code, it was possible to define limits and loops when the program was invoked. For instance, consider the program:

1.1 Type X.

Normally if one invoked this in a fashion similar to BASIC's RUN:

Do part 1.

It would produce:

0

However, one can modify this behaviour by adding a loop construct to the invocation:

Do part 1 for X = 1(1)5.

Which would produce:

1 2 3 4 5

This allows formulas to be constructed in programs without having to be placed within loops. Looping, if desired, can be provided by the user when they start the program.

Expressions and propositions
A unique feature of JOSS was its handling of logical expressions. Most computer languages offer some way to form a multi-part mathematical expression, for instance, which sets the variable x to the value 9. JOSS expanded on this concept by clearly defining the concept of the "proposition", an expression that returns a logical value, true or false, instead of a numeric one. They were mostly seen in If statements, as in the examples above, but the boolean value could also be stored in a variable directly, or one could convert true to 1 and false to 0 using the tv (truth value) function.

In addition to propositions, JOSS also had the concept of "conditional expressions". These consisted of strings of propositions along with code that would run if that proposition was true. This allowed multi-step decision trees to be written in a single line. They serve a purpose similar to the ternary operator found in modern languages like C or Java, where they are used to return a value from a compact structure implementing if-then-else. JOSS' version has any number of conditionals, not just three, so it is more of a compact switch statement than a compact if-then.

This example recreates the function of the sgn function:

Let s(x)=[x=0:0; x>0:1; x<0:-1].

This defines a function "s" which takes a single parameter, "x", and makes three consecutive tests against it. Whichever test succeeds first returns the corresponding value after the colon.

Ranges
Another advanced feature of JOSS was that it had the concept of a range as a built-in type that could be stored and manipulated. Ranges are normally found as the inputs to for loops, where they are part of the syntax of the loop itself. For instance, in BASIC one writes a for loop using this basic syntax:

This will perform a loop that assigns I the values 1, 3, 5 and then exits.

JOSS used a somewhat obscure format to define the limits of the loop. The equivalent code in JOSS would be:

I=1(2)5

Note that this code does not include a for. That is because in JOSS, ranges are first-class citizens of the language, not something that is part of a loop as in BASIC. Ranges can be defined and used in many contexts outside loops. For example, here is a conditional expression that evaluates the factorial of a parameter x:

Let f(x)=[x=0:1 ; fp(x)=0:prod(i=1(1)x:i)].

In this example, there are two main propositions, separated by the semicolon. The first, on the left, states that if the parameter x is 0, the condition should immediately return 1. If that proposition fails, it moves to the second test, on the right. This one checks if the fractional part of x is zero (i.e., it is an integer), and if so, it calls the prod function to multiply a range of values. The prod's parameter is also a proposition, but in this case, the test is replaced by a loop iterator that runs from 1 to x stepping by 1. If that proposition is true, which is it for all values of the loop, it returns the index i. This causes a series of values to be sent into prod from 1 to x.

The combination of these features allows for complex functions to be written in a few commands. This sort of functionality has only become common in much more modern languages, which typically use iterators or a map function to provide the same outcomes. JOSS's capability to combine decisions and loops in a compact form is unknown in other languages of the era, including offshoots like FOCAL.

Set
The Set command assigns the results of an expression to the specified variable. Equivalent to BASIC's LET. 01.30 Set p=3.14156. 01.60 Set i=l*(r/100)*t.

Set was optional when used in direct mode, where one could type without the Set command. This was not allowed in indirect mode, in contrast to BASIC.

Let
Let was used to define user-defined functions. Equivalent to BASIC's DEF FN.

Let t(x)=sin(x)/cos(x). Set j=t(1.1). Type j.

Let can also be used to set the value of a variable using a formula consisting of a constant:

Let x=5.

From that point, it can be used identically to one created using Set. There is a subtle difference, however, when this X is referenced in code, the value will be calculated by evaluating the right-hand side. A Set is only evaluated once, so it is much faster.

The system generally suggested using Let only in direct mode, saving them out for use in a program by inserting them at the top or bottom of the file. This avoided the Let being called multiple times during execution, as it would only be called once during the loading process.

Demand
The Demand takes a list of variables and stores the user input in variables. The optional as qualifier added a custom prompt. Equivalent to BASIC's INPUT.

01.01 Type "What is your age?". 01.02 Demand A. 01.03 Type "You are", A. 01.04 Demand H as "What is your height?". 01.05 Type H,"? That tall?".

Type
The Type command outputs one or more items separated by commas. In its basic form it is equivalent to BASIC's PRINT. However, Type includes a number of optional forms that make it highly overloaded, performing a range of unrelated output tasks.

When used to print values, the parameters can be variables, literal strings surrounded by double-quotes, and the special _ character that produces a line feed. Type also supports formatted output using format strings. See the section on Form below for details.

Type is also used as the equivalent to BASIC's LIST statement, writing out the program. For instance, Type step 1.1. will print out a single line of code, while Type part 1. will print out the entire part, and Type all. prints out the entire program.

Further, it can also be used to print lists of internal values. Type all values. produces a list of all variables and their values, while Type size. prints out the program size. Keywords include size, time and users.

Page
Page triggers a page feed on the special JOSS terminals. JOSS would normally send a page feed when the terminal reached line 54 on the paper, so if one wanted to ensure a block of data would not be split in half, one could:

1.10 Page if $>44.

$ is a pseudo-variable that returns the current line number.

Line
Line triggers a line feed on the special JOSS terminals.

To
The To command jumps program execution to the specified part or step number, using To part 1. or To step 1.1. respectively. It is the equivalent of BASIC's GOTO. Contrast with Go, an indirect command used from the command line that starts programs, the equivalent of BASIC's RUN. 01.01 Demand A as "TYPE A NUMBER". 01.05 To step 1.01. 01.10 To part 1.

Do
Do is similar to To, but branches to a subroutine. As with To, you can Do part or Do step. If a step is provided, that single line is run and then returns to the statement after the Do. If a part is provided, execution starts at the first line of the block and continues until the end of the block is reached or a Done statement is encountered. 01.15 Do step 7.24. 01.16 Do part 8.

Do had one special short form for looking in keeping with it being very common in most programs. This used the times modifier instead of a normal for, in the case for simple loops. So the following lines are equivalent:

Do part 1 for i=1(1)5. Do part 1, 5 times.

JOSS maintains a pointer to the currently executing line, which a Do would change. However, it included a special "parenthetic do" that could be used in direct mode to test certain sections of the code without changing the main pointer. For instance, if the program stopped due to an error and it was not clear which section caused the problem, one might test a particular subroutine with:

(Do part 2.)

Done
The Done command returns from a subroutine call. As subroutines return automatically when the end of the part is reached, Done is only required for returning early, and is often used with a conditional. Equivalent to BASIC's RETURN. *Routine to ask the user for a positive value and repeat until it gets one 01.10 Demand X as "Enter a positive value greater than zero". 01.20 Done if X>0. 01.30 To step 1.1

Stop
The Stop command terminates execution of the program and returns control to the editing environment. Equivalent to BASIC's END or STOP, although BASIC's STOP is intended to allow CONT to pick up execution at the same location, a feature that has no direct equivalent in JOSS's workspace-oriented system. 01.10 Type X. 01.20 Stop.

Go
Available in direct mode only, Go is the equivalent to BASIC's RUN and CONT, depending on whether a program is currently stopped due to an error or Stop command being encountered.

Cancel
Another direct-mode-only command, Cancel is used when the program has stopped for an error and the user wants to reset the program, which it does by clearing the program counter. A Go would pick up at the last location, but issuing a Cancel makes Go start at the top again. If the current breakpoint was due to a parenthetical (Do.), one can issue a parenthetical cancel, (Cancel.), to stop just that sub-execution and allow a Go to continue at the last non-parenthetical line.

Math
JOSS stored all numbers as radix-10 floating point.

JOSS contained six mathematical operators:
 * + for addition
 * - for subtraction
 * · for multiplication (the interpunct, not period)
 * / for division
 * * for exponents
 * ... for absolute value, with an expression in the middle

Mathematical expressions could use and  [] interchangeably in matched pairs to establish precedence. For instance:

1.30 Set A=|-10·[5+1]·(1+5)|.

Would produce 360.

Functions
The language contained the following built-in functions:

Math

 * sin - Sine of an angle given in radians
 * cos - Cosine
 * arg - Takes X and Y values of a point and returns the angle between that point and the x-axis
 * log - Naperian log
 * exp - Natural base to the power of the argument
 * sqrt - Square root
 * sgn - Sign of the argument, 0 returns 0, -ve values -1, +ve +1
 * ip - Integer part of the argument, ip(22026.4658) returns 22026
 * fp - Fractional part, returns .4658
 * dp - Digit part, returns 2.20264658
 * ep - Exponent part, returns 4, the location of the decimal

Boolean

 * tv - Truth value, returns 1 if the expression is true, 0 otherwise

Looping functions
JOSS also defined a number of functions that performed looping internally, in order to avoid the programmer having to write a For loop to perform simple tasks like summing a series of numbers. The parameters could be either a list of simple expressions separated by commas, or a range construct whose command could be any statement or function call.


 * max - Maximum value of the provided expressions
 * min - Minimum
 * sum - Sum
 * prod - Product
 * first - First item in the list that matches a condition, returns that result

File management
The JOSS system used a hard disk to store user programs in an allocated space. Within that space were a number of files that were referred to using a multi-part filename consisting of an integer and a five-letter name in parentheses, for instance, 123 (hello). The integer part is the equivalent of a directory, and the name is the sub-file within it, maintained by JOSS itself.

Files are written with File all as item filename. and loaded with Recall item filename.. One could also read or save only certain parts of the workspace, for instance File part 1 as item filename. to save a single routine to a file. Additionally, one could set a default file to which all references were assumed with Use item filename. Files could be deleted with Discard.

Sample program
1.1 Demand p,q. 1.2 Stop if q<0 or r(q,2)=0. 1.3 Set a=1. 1.4 Do part 2 while q>1 and a≠0. 1.5 Type a in form 3. 1.6 Stop. 2.1 Do part 20. 2.1 Do part 11 if p<0. 2.2 Do part 12 if p≥q. 2.3 Do part 13 if p=0. 2.4 Done if a=0. 2.5 Set p=p/4 while r(p,4)=0. 2.6 Do part 14 if r(p,2)=0. 2.7 Do part 20. 2.8 Set a=-a if r(p,4)=r(q,4)=3. 2.9 Set s=p, p=q, q=s. 2.95 Do part 20. 11.1 Set a=-a if r(q,4)=3. 11.2 Set p=|p|. 11.3 Do part 20. 12.1 Set p=r(p,q). 12.2 Do part 20. 13.1 Set a=0, p=1, q=1. 14.1 Set a=-a if r(q,8)=3 or r(q,8)=5. 14.2 Set p=p/2. 20.1 Type p, q in form 1 if a=1. 20.2 Type p, q in form 2 if a=-1. Form 1: " L(%.0f,%.0f)  =" Form 2: " -L(%.0f,%.0f)  =" Form 3: " %.0f\n"

Note that this is not an original sample, but rather one from a modern simulator. There are some syntactic differences from the original JOSS language.