MyAda: A Cleaner Syntax for Ada

Ada 95 is a great programming language with an excellent fundamental design and is highly recommended for safety-critical systems. However, Ada has an awkward, "klunky" syntax, and I propose to simplify it by borrowing a few basic features from Fortran 95, Python, and other languages. I will call the new dialect "MyAda".

MyAda maintains all the safety features and other advantages of Ada and can be converted into standard Ada 95 (and back) with simple preprocessors. Existing Ada compilers can still be used, therefore, and programmers working on a team using Ada can use MyAda without anyone else on the team even knowing (in theory).

I had originally come up with seven proposed changes to Ada syntax, but I was only able to implement the first three in MyAda. Fortunately, they are the most important three. Here are the three changes I actually implemented in the MyAda preprocessor, which I wrote in Python:


back to My Ada Page


Here are the other four changes that I suggested but did not implement in MyAda:


back to My Ada Page


Eliminate Semicolons

Eliminate semicolons, except for combining multiple statements on a single line, as in Python and Fortran 95. Use "\" (backslash) to continue a statement on the next line when necessary. Semicolons after each statement are unnecessary clutter, and their omission causes many nuisance compilation errors.

The original motivation for semicolons was to allow "free form" code, in which the logical structure of the code is independent of line breaks. This desire for freedom in formatting was probably an over-reaction to the overly rigid textual structure of Fortran and other early languages, which were designed in the era of punch cards. In reality, however, if code was actually written without regard to line breaks it would be virtually unreadable, and no competent programmer would ever seriously write such code. Well structured code has a logical indentation structure, and indentation structure obviously depends on the line breaks preceding the tabs.

The simple fact of the matter is that most lines of code contain a single statement. The requirement to put a semicolon after each statement therefore clutters the code unnecessarily and is silly. Why not just let the end of the line serve as the end of the statement, as in Python and Fortran 95? If a programmer wishes to be concise and put multiple statements on a line, the statements can be separated with semicolons. Rather than clutter code with unnecessary symbols, why not use special symbols only for special cases? The code will look much cleaner, and those nuisance compilation errors due to missing semicolons will be eliminated.

Some Ada stalwarts argue that mandatory semicolons make the code more explicit by clearly demarking the end of each statement. That is true, but even with semicolons another statement could appear on the same line, perhaps starting in colunm 100! In either case, the reader of the code must visually scan all the way to the end of the line to be sure not to miss anything. Semicolons add absolutely nothing in this regard.

If statements end by default at the end of the line, then some method is needed to tell the compiler when a statement will continue on the next line. The traditional line wrapping symbol in scripting languages is "\" (backslash), and it will work fine in Ada too.

Long expressions that need more than one line can often be avoided by wise use of intermediate variables, and that usually makes the code clearer anyway. The need for multiline expressions is therefore a poor excuse for requiring a semicolon after each statement. Function and procedure calls often require several lines, but the use of backslashes can be avoided in those cases because an opening "(" that is yet to be matched by a closing ")" tells the compiler that the call must continue on the next line. Consider, for example, the following procedure call:

    Some_Complicated_Procedure ( -- no backslashes needed
        Argument1 = variable1,
        Argument2 = variable2,
        Argument3 = variable3 )

In this case, no line-wrapping backslashes are needed because the opening "(" has been strategically placed on the first line of the procedure call. This strategy greatly reduces the number of line-wrapping backslashes that will typically be needed.

Another trick is to let the mathematical operators "+", "-", "*", and "/", when they appear at the end of a line, automatically indicate that the statement continues to the next line. This is natural since these operators cannot possibly appear at the end of a valid statement, and it eliminates most of the remaining need for explicit line continuation operators, which should be fairly rare.

Use "=" for Assignment

Use "=" rather than ":=" for assignment. Virtually all of the most popular programming languages use "=" for assignment, which is simpler and perfectly adequate. Use "==" for equality testing (note that Ada never allows assignment within an "if" test).

The most popular programming languages ever designed are Fortran, Cobol, Basic, C, C++, Java, Perl, and Python. They all use "=" for assignment. Other languages that use something else for assignment are typically defunct or far less popular. That includes Pascal, Modula, Forth, and Tcl, for example.

Other languages that use "=" for assignment include the popular proprietary scripting languages Matlab and Mathematica. Matlab is designed for vector/matrix computations, control system design, and advanced optimization. Mathematica is a very sophisticated symbolic math system.

Ada uses ":=" for assignment, as do Pascal and Modula. This is inconsistent with all the major languages, and it causes innumerable nuisance compilation errors among Ada beginners and programmers who must switch back and forth between Ada and more popular languages.

Many Ada purists believe that using "=" for assignment somehow violates mathemetical principles. After all, the statement x=x+1 is mathematical nonsense. But assignment statements that do not contain the left-hand variable on the right-hand side make perfect sense. For example, the statement x=3 becomes true in a mathematical sense immediately after it executes.

Einstein said, "Everything should be made as simple as possible, but not simpler." The symbol "=" is the simplest possible symbol for assignment. The fact that even Mathematica uses it essentially proves that it is perfectly appropriate. Mathematica is perhaps the most advanced mathematical software available today.

Ada currently uses "=" for equality testing. However, another symbol must be used to distinguish equality testing from assignment. Since assignment is far more common than equality testing, assignment should get the best symbol. Several major languages, such as Java, C, C++, and Python, use "==" for equality testing, and it would suit Ada fine.

C and C++ allow assignment within an equality test. That was a huge mistake because it allows the common error of mistyping "==" as "=" to go undetected by the compiler. Python has a very simple solution: do not allow assignment within a conditional test. That is appropriate for Ada too.

Use "=" for Passing Arguments by Named Association

Use "=" instead of "=>" for passing arguments by named association, as in Python and Fortran 95. Again, it is simpler and perfectly adequate.

Like Fortran 95 and Python, Ada allows subprogram arguments to be passed by named association. This is a great feature for a couple of reasons. First, it yields more readable code, and second, it prevents errors due to passing arguments in the wrong order. Also, if the order of the arguments in a subprogram is changed, the calls will still work properly.

Although Fortran and Python use "=" for named association, Ada uses "=>". All the arguments above regarding assignment apply here as well. Basically, the symbol "=" is simpler and perfectly adequate. But another problem with "=>" is that it points in the wrong direction! It should really be pointing left, but "<=" is already used for "less than or equal to".

Use ":" for Ranges

Use ":" instead of ".." to denote a range of numbers, as in Fortran, Python, and Matlab.

This is a minor point, but ":" is used by Fortran, Python, and Matlab to denote a range of numbers. Why not be consistent with a de facto standard?

The symbol ".." can be confusing when used without spaces, as in (1..3), because it looks like a decimal point. Hence in practice it is often used with spaces, as in (1 .. 3). That means it takes up four characters rather than one. Programmers who do a lot of work with vectors and matrices no doubt prefer (1:3) to (1 .. 3).

Add Augmented Assignment Operators

Add assignment operators such as "+=", "-=", "*=", and "/=". These operators produce cleaner code. They could also facilitate much more efficient vector/matrix operations if integrated into the core language.

One of the objections to using "=" for assignment, as discussed above, is that statements such as x=x+1 are mathematical nonsense. But incrementing a counter is one of the most common operations in programming. Many languages, including C, C++, Java, and Python, provide assignment operators that allow x=x+1 to be written as x+=1. That form eliminates the mathematical nonsense, and it is also simpler. The advantage becomes clearer for a longer variable name. Compare, for example, the two forms

    Airplane.Aileron_Angle_Command :=
    Airplane.Aileron_Angle_Command + delta; -- old form

    Airplane.Aileron_Angle_Command += delta -- new form

But the potential advantage of the assignment operators is more than cosmetic. If they were added to the core language, they would allow much more efficient vector/matrix and other operarations. Consider, for example, the following matrix addition:

    A = B + C -- inefficient form

This requires the construction of a temporary matrix to hold the sum, followed by a matrix assignment. But the equivalent form

    A = B
    A += C -- efficient form

can perform the addition directly on the elements of matrix A, eliminating the inefficient temporary matrix construction and the assignment. In many cases the less efficient but cleaner form is tolerable, but in many other cases it is not. In a real-time application or a computationally intensive Monte Carlo simulation, for example, the inefficient form would be very undesirable.

Another example is dividing a matrix by a scalar. For example, A/=2.0 is much more efficient than A=A/2.0. Unfortunately, the operator "/=" is already defined as "not equals" in Ada, so "!=" will have to be used instead for "not equals".

Note that the efficiency of the assignment operators can be realized in standard Ada with procedures. For example, a procedure MatrixAdd(A,B) could be defined to add B to A in place with the same efficiency as "+=". However, a short procedure name that makes clear exactly what is happening is difficult to find. The assignment operators make it crystal clear in two characters.

Use a More Natural Declaration/Initialization Syntax

Use a more natural declaration/initialization syntax. The assignment is to the variable, not the type, and the syntax should show that. The same applies to default subprogram arguments.

This proposed change is best illustrated by example:

    count: integer := 0;  -- old syntax
    count = 0: integer  -- new syntax

The new syntax correctly show that the variable count, rather than the type integer, is initialized to 0. It is also more consistent with assignment.

Let "Use" Imply "With"

Let "use" imply "with" so files need not be cluttered with both "with" and "use" for the same package. This would not preclude the explicit use of "with" if that is deemed preferable.

back to My Ada Page

RussP.us