- Introduction A computer program attempts to transfer a wish your clever but messy brain has into instructions for a dumb but orderly computer to do. If you are new to programming you have to learn about the different layers of symbols and meanings in any program written in a particular language. If you have already learned a language you will see how the rules of Ox compare to the languages you have learned.
- Comments and Whitespace
- Identifiers
- Keywords and Symbols
- Constants and Literals
- Constant Arrays and Enumerations
- Things (variables etc.)
- Statements
- Preprocessing
- Comments and Whitespace A comment is text inserted into a computer program that is ignored by the computer when running the program. In this sense, comments are completely unessential to what the program does. However, comments are completely essential for you, other humans, and in some cases other computer programs to understand what your think your program does.
Anything between/* This is an Ox comment */
/*
and*/
is considered a comment in Ox. This kind of comment can be nested (unlike C and C++): Why would/* A comment /* a comment inside a comment*/ */ println("hello world");
/*
be used as a delimiter? The reason is that/*
is never in a valid mathematical expression so it is safe for the language to use it as a special item. The other thing to note is that a single comment of multiple lines can occur in the program. This allows you to expand and format your comment to make it easy to read. Anything from//
to the end of the line is also comment. Note that this kind of comment also has a beginning and an end, but the delimiters are not symmetric as in// This is an Ox comment … until the end of the line
/* … */
comments. We get end-of-the-line by hitting theEnter
key. It turns out that doing this actually inserts two special characters into your program that are not printed. One character says to return to the first column of the page. The other character says to create a new line. So really these comments are delimited by// … <CR><LF>
. These comments make it easy to add an aside to your code. It also makes it easy to temporarily remove one line of code that you may later want to make operational again. Some computer languages like Python treat lines of code and spaces at the start of lines as important to the meaning of the code. Ox follows in the tradition of languages that do not care about lines (with a couple of minor exceptions). Each of the following code segments are the same in Ox:one = cons + 1; // comment /* two = cons + 1; // comment inside a comment */
The first two are probably clearer than the others because of the random patches of whitespace in the latter examples. You will develop your own style of programming in terms of adding or deleting whitespace. It is important for both you and readers of your code that your style helps display the logic of the code.println("hello world");
println( "hello world" );
println( "hello world") ;
println( "hello world" );The use of indentation in Python to 'structure' the code is perhaps the biggest difference between Ox and Python syntax. Ox uses braces,
{ }
, to create blocks of code instead of indentation. And it uses;
to end statements instead of the end of a line or ENTER.- Things Can Go Wrong with Comments While comments are essential for explaining (documenting) your code they do not do anything. They are removed by the process that implements or executes your code (discussed in the next chapter). But this means that comments can cause problems. First, you might not close a comment properly:
/* My hello world program!! /* main() { println("hello world"); }
Here // Print hello. decl h="hello"; println(h);
The - Identifiers An identifier in Ox is the name of
oxkeywords.txt 1: array default goto private switch 2: break delete if protected switch_single 3: case do inline public this 4: catch double int return throw 5: char else matrix serial try 6: class enum namespace short virtual 7: const extern new static while 8: continue for operator string 9: decl foreach parallel struct
Do not pick any of these as identifiers for things in your program. Your code will be misinterpreted by Ox. Ox will probably notify you of the problem. If you try to declare a variable with one of these names it will complain (try it!). Our programs will contain only a few of these keywords, but if you look at the full Ox syntax you will see each of them plays a special role just like - Constants and Literals
- Various ways of writing 1.0:
1.0 1. 0001.0 1.00000 1E0 10E-1 0.001E3
Various ways of writing 1/10:.1 00.1 .10000 0.10000 1E-1 10E-2 0.001E2
< 0, 1, 2; 10, 11, 12 > < 0.0, 0.1, 0.2 > < 1100 >
which are respectively a 2 by 3 matrix, a 1 by 3 matrix and a 1 by 1 matrix, the first constant is:
0 1 2 10 11 12
The index of each row is one higher than the previous row. Within each row, the column index of an element is one higher than that created with the previous element in the same row. An empty matrix can be written as:
< >
At this point you might not see a reason to allow such a thing, but it turns out to be a useful when the program is going to construct a matrix bit-by-bit. Starting with an empty matrix and then building is common in larger programs. Further, Ox has a sophisticated way to create large and complicated matrix constants. For someone already familiar with a similar language it would make sense to discuss these features now. However, in this book we return to this material later.
03c-const-matrices.ox 1: #include
2: main() { 3: decl M ,x ; 4: M = < 0 , 1 ; 2 , 3>; 5: x = exp(1.0); 6: println("M = ",M,"\nx = ",x); 7: } - Constant Arrays and Enumerations The thing that Ox documentation calls an array constant might also be called a list constant. A list constant is created in your code by placing constant items in curly brackets separated by commas:
{ "A crazy constant list" , 5.0 , 99 , TRUE , <1.0;3.0;5.0> }
Here are some examples,:
03b-const-arrays.ox 1: #include "oxstd.h" 2: 3: main() { 4: println("Start/Finish", 5: { "hello, world", "goodbye, cruel world"} 6: ); 7: println("Here are some random things in a list:", 8: { 12, 99.5, "pi" } 9: ); 10: println(" Here is a list of lists: ", 11: { {"integers", -5 , 99, 0}, 12: {"doubles" , 22.3, -0.5 }, 13: {"strings" , "a" , "b" } } 14: ); 15: 16: }
Run this program to see what is printed. A constant list might contain another constant list, so this is a recursive definition. The constant can itself be an array constant as shown in the last example. It is possible to do a great deal of computational economics in Ox without using ox arrays (lists). However, lists can be very useful in more complex code and they play a role in making you output from Ox look nice.
decl v; v = 5; { 12, v, 99.1}
The reason is that 03a-enums.ox 1: #include "oxstd.h" 2: enum{Zero,One,Two} 3: enum{OFF,ON} 4: enum{MinusOne=-1,Zed,Three=Two+One} 5: enum{UNDEFINED=-2,WRONGTYPE=-3,BADINPUT=-4} 6: 7: main() { 8: println(One," is the loneliest number\n", 9: Two," can be as bad as ",One); 10: println("A valid name for ",MinusOne," is MinusOne."); 11: println("You can do simple arithmetic in an enum: ",Three," equals ",Two," + ",One,": ",Two+One); 12: println("But enums are not variables. Uncomment the next line to see an error."); 13: //ON = 1-OFF; 14: }
Run that code and see how the identifiers in the enum get replaced with integers. In other words, //Hidden Counter Value enum { // 0 first , second // 1 , fourth=3 // 3 , sixth=fourth+2 // 5 } enum { another_first } // 0
The enum's above create five identifiers that can be used in the program: - Things Physically Exist During an Ox Program The official Ox term for a thing is an object. However, "object" is sometimes used to refer to one particular kind of thing. So here I use "thing" to refer to anything in your program that has a particular physical location in computer memory assigned to it while your program is running. Most things in basic Ox programs are either a variable or a function.
f(a); // declare a function named f but do not define it yet decl y; // declare a variable named y g(b) { // declare a function g and at the same time define it. println("b= ",b); }
03e-things.ox 1: #include "oxstd.h" 2: decl joe; 3: f() { 4: decl sally; 5: sally = 5; 6: } 7: main() { 8: joe = "hi"; 9: f(); 10: }
There are two variables in the code, int
- an integer, holding values like 5 or -493
double
- a real number holding values like 13.2 or -3.19417.
matrix
- a two-dimensional grid of real numbers which can be manipulated as a whole, such as $\matrix{1&2\cr 3&4}$.
string
- zero or more characters as in
hello, world
. array
- a list of Ox things (technically, references to things). The word array is often used more generally, so these notes will usually use
list
instead. - Modified
decl
statements
You can modify how a variable is stored by adding one (and in some cases two) of three keywords to the 03c-const-decl.ox 1: #include "oxstd.h" 2: 3: decl y; 4: 5: const decl answer = 42; 6: 7: main() { 8: y = 5; 9: println("y= ",5," and the answer is ",answer); 10: y = "love"; 11: println("Now the word is ",y); 12: //Uncomment the next line to see that you can't mess with const's 13: //answer = "love"; 14: 15: // const's can't be declared inside a function: uncomment the next line to see another error 16: // const decl v = 12; 17: }
In the code - Statements In Ox, a statement does something. A statement is like a complete sentence in English, except that statements in Ox end with a semicolon
- Preprocessing Directives The last element of an Ox program introduced now is ironically often at the top of the program. It happens before anything else (hence the term preprocessing). The symbol
#include "oxstd.h"
This directive tells Ox to:
- Find the file named
oxstd.h
. If it can't be found everything stops and the program never runs. - Insert the contents of the file as if the programmer had typed them.
- NOTE: If Ox cannot find a
.h
file then it will also look for theoxstd.oxh
file. This is a special feature related to header files.
As with any other choice, there are tradeoffs between different programming languages. Many of these tradeoffs boil down to: Pay me now or pay me later. Some languages are designed to be "easy" to learn. Ox is not like that. Its rules are a lot like C and C++, which were not developed to be "easy". However, for doing economics Ox is much easier than many if not all other languages.
This section introduces you to these overall features of an Ox program without delving into many details.
Ox, like many languages, have two different kinds of comments. The first kind is text that falls between two special sequences of characters, /*
and */
. Special characters that begin and end different kinds of code in a program are called delimiters.
/*
does not close out the comment above (should be */
). Everything past main()
is ignored because it is still in the comment. The other problem is a deleted end-of-line:
decl
statement is accidentally on the same line as the comment. A syntax error occurs because h is not declared.
As you start to write more complicated programs make sure the sophistication of your comments keeps up with the code. Notice this does not mean the quantity of comments have to expand as your code does.
something. The next section talks about different kinds of things in Ox. In our programs, most identifiers will be the name of variables and functions. As with all other languages, Ox has rules for what is a valid identifier. In Ox, identifiers are made up of letters and digits. The first character must be a letter. Underscores (
_
) count as a letter. Identifiers can't start with a digit because Ox will think it is a number (numbers are not identifiers). Identifiers can't have any other special characters other than _
, because many of these characters have special meanings already. For example, +
means addition, so you can't use
a+b
as an identifier. If you tried, Ox would think you are giving it an instruction: add b to anot referring to a thing named a+b. Identifiers are also case sensitive. So
abc
and ABC
are two different identifiers.
What about
? According to the rules above, it is not an identifier because hello
is neither a letter nor
_
. Instead it is a constant string (also called a literal string) rather than the name of something. Sometimes Ox will use strings as labels for rows or columns of output. Again, that is not the same thing as an identifier.
There are some other rules about identifiers, both in Ox and other languages. For example, it would be confusing in English if someone's name was Me
, or even worse, me
. If we read Me says he is going to the store.
it is hard to tell what the meaning is. Or, what would Give it to me!
mean?
Even though Me is otherwise a perfectly reasonable English identifier most parents would not torture their kids by giving them such a name, although Frank Zappa named his kids Moon Unit and Dweezil. They seemed to turn out okay. The jury is still out on X Æ A-Xii Musk. Poets like to play with the implicit rules of identifiers, including e e cummings, kd lang, and .
The same is true in a programming languages: some valid identifiers are off limits to the programmer because they mean something special in the Ox language. In a programming language, such special identifiers are called keywords and/or reserved words. If you make the mistake of using an Ox keyword as an identifier it will probably create a syntax error, but Ox may have trouble telling you what the error is.
Table 1. Keywords in Ox 9.0
meand
theplay special roles in English.
Further, there are names that are valid identifiers and not keywords that are still bad ones to use. For example, you could use println
as an identifier because it follows the rules and is not a reserve word. But that would be a bad idea if you ever want to print something out from your code.
If you look at a well-written Ox program that does some real work and count the characters in the file you would probably notice that it consists mostly of comments, whitespace and identifiers. The next most frequent components would probably be constants and literals. These come in different flavours which should be fairly natural, although some of the distinctions may not be clear until later.
First, we have already encountered a literal:
. This is a string constant. There are some details about strings best left for later since most strings in your code will be simple like hello, world
hello, world
. Next, we have integer constants such as 2, -33, 99999. A sequence of digits, with possibly a leading -
is an integer constant.
A double constant has a name that won't make sense because it comes from programming concerns in past decades. But essentially a double constant is a real number. As text it consists of an integer part, a decimal point, a fraction part, and optionally e
, E
, d
or D
and an optionally signed integer exponent. Either the integer or the fraction part may be missing (not both); either the decimal point or the full exponent may be missing (not both).
We now encounter a first important feature of Ox as a tool in economics. Ox understands vectors and matrices. This is not true of all languages. For example, C has no notion of a matrix as we have, which is one of the motivations for an economics student to create a language like Ox. A matrix constant lists within <
and >
the elements of the matrix, row by row. Each row is delimited by a semicolon, successive elements in a row are separated by a comma. For example:
Here is an Ox array (or list) that is not constant:
v
is a variable (discussed below), and variables are not constant. Certainly variables can be put in a list, it's just that it will then not be a constant list. That means it may create an error when only a constant list would be allowed.
Ox inherits from C the notion of an enumeration or simply enum
. (Note that enum
appears on the keyword list.) An enumeration is a sort constant list of integers. The enum itself contains indentifiers, but each identifier will be replaced with the integer it matches up to anywhere it appears in the program. Another way to think of an enum
: it allows your program to give integers a meaningful name. You might think of an identifiers in an enum as aliases for integers.
One
is now exactly the same as putting 1
in your code.
Here is another explanation to explain what happens in that code. At the start of the enum statement Ox sets a "counter" to 0. Unless you put =
in the enum list the counter is incremented by 1 after each comma. The identifier you list then takes on the value of the counter. Putting = in the enum followed by an integer resets the counter to whatever follows the equal sign. Here is the idea:
first, second, fourth, sixth, another_first
. The comments show you what value each identifer will take on. If in doubt, just print out the value of items in the enum. The first enum starts at 0, increments automatically to 1 after the first comma, then gets set to 3 and then gets set to 5 because fourth+2 ≡ 3+2 = 5
. The second enum resets to counter to 0. So now there are two different names for 0 available in this program: first
and another_first
.
So in the program MinusOne
gets the value of -1. Then, unless there is another equal sign, the next item in the enum will be an alias for -1+1 = 0. So Zed
is an alias for 0. Enums can also include very simple arithmetic, as in the case Three=Two+One
. Python has something called enum that has some similarities to Ox or C enums, but is more flexible and less simple to set up.
Notice that Zero
, OFF
and Zed
are all aliases for 0. Any integer can have multiple aliases in your code from different enums. Why allow this? Without using enum{}
your code may have lots of integer constants like 0
or -1
. Sometimes 0 will mean one thing, at another point it means another. If your code changes you might change some of these 0s to 1s but keep others the same. Further, 0
does not tell us what it means, whereas OFF
can mean something even if it is just an alias for 0
.
Ox has some built-in or pre-defined enums{}
. One that you should learn to use in order to make your code more reliable is:
enum{FALSE,TRUE}
In other words, your program can replace the integer 0 with FALSE
and the integer 1 with TRUE
. (You do not have to include the enum definition because it is part of Ox.) This reflects something discussed in more detail in the next chapter, that the number 0 is associated with something being false and 1 with it being true.
New programmers are easily confused by things like constants and enums. One reason is that this explanation that Ox has a hidden counter for each enum statement happens before your program starts executing. Other things like calculating the square of a value and storing it somewhere happens while the program executes.
It may seem strange to think of an aspect of a computer program as a physical thing. This physical location is an amount of computer memory is associated with the thing
in question. Memory consists of semi-conductor bits which are actual physical locations on the memory chip. On the other hand, in enum{Off,On}
On
and Off
are not things because they are just tags for the numbers 0 and 1. Before your program begins to execute the Ox system replaces those tags with the digital value of the integer. So as your program runs On
is not associated with a location in memory. So an enumerated value like Off
above is not considered a thing (or an object in the official Ox lingo).
A thing in Ox must be declared before it is used (referred to). If you try to use a thing in Ox before it is declared then Ox will complain and stop executing your program. Variables are declared with the decl
operator.
Python does not require you to declare variables before you assign a value to it, so if you know Python you have to get used to this in Ox. There are pros and cons to requiring explicit declaration, so this does not make Python better just easier to use for simple programs.
Functions are declared by simply listing the function name and its arguments. This can be done separately from the definition. Or both the declaration and definition can be done at the same time. (The possibility of separating them makes it easier to break a large program into separate files, as discussed later.)
In Python you put the keyword
def
before the name of the function when defining it. In Ox you simply define it by placing {
after its header.Languages like C, FORTRAN require that a variable's type is specified when it is declared. If you create an integer named j
in C then j
will be interpreted as an integer at all times during the program. These are examples of statically typed languages. Ox and Python are examples of dynamically typed languages. If you decl j
it starts as uninitialized (no type). It can then become an integer, change to a string and end up as a function while your program executes! If you have only coded in statically typed languages before this can be a bit confusing.
Basic Types of Ox Variables
Here is some text from the Ox documentation. It probably won't mean much to you but if you are a trained programmer it might be helpful:Variables in Ox are implicitly typed, and can change type during their lifetime. The lifetime of a variable corresponds to the level of its declaration. Its scope is the section of the program in which it can be seen. Scope and life do not have to coincide.Is that clear? Probably not. The ideas of "scope" and "lifetime" are hard to understand without some knowledge of how programs actually run on the computer. But within a given language like Ox their meanings can be learned by trial and error and lots of examples. Here is some code and an explanation of the concepts to get started:
joe
and sally
. The scope of joe
is everywhere because it is declared outside of any curly brackets. That means joe
can be seen and used anywhere below its declaration. The scope of sally
is simply the statements between {
and }
that surround it. So the main function cannot see sally
(try printing sally inside main and see what happens).
The lifetime of an object is when the variable exists. Since joe
is global (declared outside any brackets), it exists the whole time the program executes. The lifetime of sally
is normally only while f()
is executing. (The contents of sally
can continue to exist after f()
finishes if it contains an object of a class, but this is not important for basic Ox programs.)
The basic Ox types are listed below. Later chapters discusses several more types and go into depth about the life of things.
What Ox calls "double" Python calls "float". (Exercise: find out why these names are used instead, for example, "real." Python is not matrix-oriented so it has no native matrix variable type. Python's "list" type is essentially the same as Ox's
array
type. Python's "tuple" type is the same as a const decl
array in Ox. Ox 8.0 does not have an equivalent to Python's dictionary
type, but Ox 9.0 will have something similar.decl
command. The main one we see in this class is making the thing a constant. (The other two are static
and extern
, which are used in classes and programs that involve multiple files.
y
is an ordinary variable. (Note that it is declared outside of main()
, something we will discuss later.) However, answer
is set to 42 and it cannot be changed later in the code. Run the example and then uncomment the lines to see what happens.
Note that enum{}
creates an kind of constant, but only integer values. On the other hand, const decl
can create any kind of Ox value, such as a matrix, a list or a string.
;
.
The reason might be obvious: periods also show up in real numbers (like 33.2) so using it to also end a statement can be confusing. So println("hello, world")
is not a complete statement, but println("hello, world");
is. The semicolon tells Ox it should have received all the information about what to do for this step in the program. Anything after ;
would either be the next statement or some other aspects of the program. So when it comes time to run the program this statement will be executed before going past the semicolon.Semicolons are Essential
One of the most common syntax mistakes students make is forgetting that semicolons are essential in Ox. Some languages like Python use the end of a line to indicate the end of a statement. In Ox, if you forget ";" you will confuse it, and the syntax error message you get won't be "you forget ;, dummy!" Getting used to this takes time, but when you see an error, often check and make sure there are semicolons at the ends of statements above the error.What makes computers and programming languages powerful is the capacity to build complex statements out of simpler ones. The most fundamental of these structures is a statement that will run a statement only if some condition holds. This is the if () then
structure in Ox. These are discussed later.
#
in Ox signals a preprocessing directive. These are like statements except Ox statements do stuff when the program is running. Preprocessing directives happen as your Ox program is being read and understood but not yet executed. We have already seen an example of this hello-world
:
#directives
are handled first, and then the program is read again. So on the second pass #include ...
has been replaced by the contents of the included file.
The only other preprocessing directive seen in simple Ox programs is #import
. This is like #include
but does more and its use is best discussed later. It is key for writing complex Ox programs that are reliable and easy to read.
Summary
- Ox programs consist of whitespace, comments, preprocessing directives, and code.
- Code includes different kinds of constants and statements
- Variables are the main
things
that take on values and change while the program runs - Variables in Ox have different types, and the type of a variable can change as the program runs.
- Ox is a matrix-oriented language. It understands and processes matrices.
Exercises
Valid Invalid ----------------------------------------- a a1 1a a_1 _a_1 doit! b c ABC a-b ------------------------------------------
02a-fix-error.ox 1: #include2: 3: main() { 4: decl println=5.0; 5: println( println ); 6: }
hello world
.03-fix-errors.ox
1: #include "oxstd.h"
2: */ A comment /*
3: /*
4: main() {
5: // println(
6: "hello, world"
7: );
8: }
- Have it create a matrix in $D$ which is a 4×4 diagonal matrix with the diagonal equal to <1 2 3 4>. (Look up diagonal matrix on wikipedia if you aren't sure what it means.)
- Use the Ox help documentation to find a function that will create the same matrix in $D2$ for you by sending the diagonal as a vector to it. Print out the matrix to verify it works.
- Use Ox help to find the way to extract the diagonal from a matrix and apply it to the matrices $A$ and $B$ in the previous exercise.
- Use Ox help to find a function that will create a new matrix from $A$ that is diagonal (sets off-diagonal elements to 0). Print out the function output to check it
https://en.wikipedia.org/wiki/Band_matrix
. Create a 5×5 band matrix with -1 below the diagonal, 2 on the diagonal, and +1 above the diagonal. enum{}
to define a best and worst in the list and print them out. That is, best
would be the index into the list that is the best (in your opinion). For example, I might create a list of some Canadian music artists:Joni Mitchell, The Band, Tragically Hip, Nickelback, Celine Dion, Drake.For me, I would define
best
as 1 and worst
as 3 in that list (although technically the Band is only 4/5ths Canadian, eh).
enum text 100-point-scale GPA ------------------------------------------ F F 00 0.0 Dm D- 52 0.7 D D 55 1.0 Dp D+ 58 1.3 Cm C- 62 1.7 C C 65 2.0 Cp C+ 68 2.3 Bm B- 72 3.0 B B 75 2.7 Bp B+ 78 3.3 Am A- 82 3.7 A A 87 4.0 Ap A+ 93 4.3
03d-letter-grades.ox
1: #include "oxstd.h"
2:
3: enum{F}
4:
5: const decl
6: gtext = {"F" } ,
7: gpct = <0 >,
8: gpt = <0.0 > ;
9:
10: main() {
11: println(gtext[F]," = ",gpct[F],"%. and GPA = ",gpt[F]);
12: }