The F Language

Software Careers Fall 1997 Dr. Dobb's Journal

by Walt Brainerd, David Epstein, and Dick Hendrickson


Walt was director of technical work for the Fortran 90 standard and is coauthor of The Programmer's Guide to F. David is the project editor of Part 3 of the Fortran standard regarding conditional compilation and author of Learning How to Program With F. Dick is one of the developers of the SHAPE Fortran 90 test suite and a 20-year member of the Fortran ANSI committee. They can be contacted at walt@imagine1.com, david@imagine1.com, and dick@imagine1.com, respectively.
Listings
Insert As hardware becomes smaller, faster, and less expensive, it seems that programming languages, compilers, and development environments are becoming larger, slower, and more complex. Although languages such as C++ and Java are powerful and attractive for many programming tasks, they are inappropriate for the extreme ends of the programming spectrum. At one extreme, they're too complex for introductory programming courses. At the other extreme, these languages have inherent ambiguities that make them difficult to optimize, and hence inappropriate for many large, performance-critical programming projects.

Novice programmers have to deal with many details, such as learning an editor, operating-system commands, and how to save code into something called a "file." A poorly chosen introductory programming language adds the lack of compile-time error checking to this overwhelming list. F, the programming language we discuss in this article, addresses such issues. A subset of the most recent version of Fortran, F retains the modern features of Fortran (modules and data abstraction, for example), but discards facilities that are difficult to teach, use, or debug. It is a safe and portable programming language. F can also be used by Fortran 77 programmers as a transition to the new concepts in Fortran 95 or in High Performance Fortran (HPF).

At this writing, F is available for Windows 95/NT, PowerPC Macintosh, and various UNIX workstations (SunOS, Solaris2, AIX, IRIX, HP-UX, DEC Alpha UNIX). An educational version of the PC Linux F compiler is available at no charge (see http://www.imagine1.com/imagine1/ for more details). Professional versions are also commercially available. (The main difference between the educational and professional versions is that the professional versions allow interface blocks and calls to non-F procedures [such as Fortran 77, Fortran 90, or C/C++]. The professional version also allows modules to be verified and compiled in one directory and used by a program in another directory.)

Consider the common error of typing "if (x=3)" when the desired statement is supposed to be "if (x==3)". C, C++, and Java all accept if (x=3) because these languages were designed for people who might want to actually make an assignment inside an if statement. Students, however, need to be told whenever possible about errors during compile time. F, Pascal, and many other languages help students with this confusion between assignment and comparison by issuing a compiler-error message. In F, the assignment and comparison is done in two steps:

x = 3
if (x==3) then
Similarly, F fixes the dangling else problem that appears in languages such as Pascal. The following Pascal excerpt is inherently ambiguous:

if x=3
then if (y /= z)
then writeln('case 1')
else writeln('case 2');
F requires that every if statement has a matching endif statement, which neatly solves this problem.

if (x==3) then
   if (y /= z) then
 print *, "case 1"
   else
 print *, "case 2"
   endif
endif
Nice Syntax

Notice that the above examples have no Pascal-like begin statement nor hard-to-find C-like "{"-"}" pairs. F statements, such as if and do, serve as the beginning of a construct; the construct is finished by a corresponding endXXX keyword.


Attribute Description
pointer/target Pointers can point only at targets or pointers.
public/private All module entities are either public or private.
intent All subroutine arguments must be declared as intent.
in,out, or inout
All function arguments must be intent in
dimension Arrays can be from one to seven dimensions
allocatable For dynamic allocation
parameter A constant
save A static local variable
Table 1: F data attributes

Also notice that F does not require a ";" at the end of a statement. Instead, the end of the line serves as the end of the statement. If the statement is longer than one line, a trailing "&" character signals that the statement continues on the next line. Since the average statement in most languages fits on one line, it makes sense to only require a special character for the less-common case.

F Emphasizes Words

Programs are written once and read many times. As a result, it's important that programs be easy to read. Unlike C, F does not have macros, compound statements, or cryptic syntactic shortcuts such as ++, &, *, or --. Figure 1 is a view of the whole F language by the names of the statements. In almost all the F statements, the first word of the statement uniquely specifies what the statement is. Experienced programmers can likely pick up most of the F language at a glance.


Organizational Constructs

  program
  use <module> <-----------------module
  endprogram                       public  :: proc-list
                                   private :: proc-list
                                 contains
                                   <procs> <--------------------
                                   endmodule                    |
                                                         ----------------
                                                        |                |
                                                    subroutine        function
                                                    use module        use module
                                                    endsubroutine     endfunction

Action Constructs
  if / elseie / else / endif
  select case / case / case default / endselect
  do / cycle / exit / enddo
  where / elsewhere / endwhere

Declarations
  type           integer          character      intrinsic      interface
  endtype        real             logical                       module procedure
  complex                                                       endinterface

Actions
  = (assignment)                  allocate       call           stop
  => (pointer assignment)         deallocate     return

Input/Output
  print          open             write          inquire        backspace
  read           close                                          rewind
                                                                endfile
Figure 1: The entire F language

F also has simpler and safer handling of pointers than does C or C++. F pointers are only allowed to point to targets or other pointers. Although this has additional pedagogical benefits, the original motivation was to allow for better compiler optimization.

The Roots of F

F is a strict subset of Fortran 90. If you're only familiar with older dialects of Fortran, you may be surprised by many of the features added to produce the Fortran 90 standard. Fortran 90 retains all of the older Fortran 77 (and Fortran 66) syntax, making it an expensive language to purchase, learn, implement, and support. By calling F a "new" language, we had the opportunity to remove some of the accumulated baggage. The result is a clean and simple language that retains the power of Fortran 90. Indeed, much of the interest in F comes from people who need to use Fortran but would like to restrict their attention to something simpler than the full Fortran 90 language.

By design, there are as few statements in F as possible but as many intrinsic procedures as possible. These different views of F can be attributed to the design goal of a minimal language with all the computational power of Fortran. Anything that could be taken out of Fortran 90 without removing desirable features, was taken out. F expressions maintain the full array language of Fortran, and only 10 percent of the intrinsic procedures were deemed redundant.

Since every Fortran 90 compiler is also an F compiler, F is already an extremely portable language. A testimony to this portability is the F compiler, whose front-end is written in F. Only a couple of procedures need a few lines of conditional compilation (soon to be in Fortran and F) for the F front end to compile and run across Windows, Macintosh, Linux, and UNIX systems. (For more information on conditional compilation, see "Conditional Compilation," by David Epstein, DDJ, April 1996.)

An F Program

An F program is defined between program and endprogram, and is syntactically much like a procedure. Like the main function in C, there can be only one program, but it can use modules to accomplish a task. It does this with use statements, which identify modules used by the current program or module. In particular, use statements remove the need for C-style makefiles. As the compiler encounters each use statement, it locates the corresponding module. This greatly simplifies program management, and even allows the compiler to choose which modules need recompiling. For example, the compiler can check if there have been any publicly visible changes since the last time the module was recompiled, rather than blindly recompiling every use of that module.

Since all overloading is resolved at compile time and all names are made available in local declarations or by using previously compiled modules, everything that requires resolution is known at compile time. This means that the process of compiling an F program (as compared to compiling an F module) can include the step often known as "linking." F compilers do not require a separate linking step, and there are no link-time errors or unresolved externals. Accidentally misspelling the name of a procedure is caught by the compiler.

Module-Oriented Programming

Modules define some related collection of data, types, and procedures, any of which can be private (only visible within the module) or public; see Listing One (listings begin on page 40). Unlike classes, modules do not have any type of inheritance. Users of a module gain access to the public members of that module. Modules can have interface definitions that allow functions and operators to be overloaded based on their type.

Data in F

Most statements in F are identified by the first word. If the first word is a type name, the statement declares a variable. Each variable can have a variety of attributes (see Table 1), indicating how that variable should be handled by the compiler.

Expressions

F supports the standard collection of arithmetic operations in expressions. It also allows intrinsic operators to be overloaded. For efficiency, all overloaded operators are resolved at compile time.

One of the most powerful aspects of Fortran 90 and F is the array language. You can conveniently refer to a single element or any portion of a large, multidimensional array. Many arithmetic operators are defined for arrays. For example, if you've defined the arrays A, B, and C as

integer, dimension(7,7) :: A, B, C

then you can write A+B to compute the element-wise sum of A and B, or A(2:3,4:5) to refer to a 22 sub-array. This makes complex array operations very compact; A(i,j) = sum(B(i,:)*C(:,j)) computes an inner product.

Numerically Intensive Programming

Mathematicians, statisticians, physicists, chemists, and other scientists have quite different problems to solve than compiler writers, application programmers, and computer scientists do. Unfortunately for the science and engineering crowd, popular programming languages and their compilers are designed and written by computer scientists. With F, those that need to write programs but do not want to focus purely on programming have the opportunity to use a familiar tool-a simple problem-solving programming language.

Listing Two shows the power of this array language, especially when combined with the notational convenience of pointers. The heat problem is to determine the temperature of any given point on a plate of metal when the boundaries are held at specific temperatures. The temperature at any given point is the average of the temperature of all the neighboring points. The statement temp = (n + e + s + w)/4.0 computes all of these averages at once; on a high-performance system, this type of computation would automatically be spread across multiple processors.

High-Performance Fortran

As F is a subset of Fortran, it is also a subset of High Performance Fortran (HPF). Currently, the HPF language design team feeds the Fortran standardization team with ideas. For example, pure procedures and the forall construct were adopted into Fortran 95 from HPF. As these and other new features are added to Fortran, they will be considered for addition to F as well.

Pure Procedures

Pure procedures are procedures that "have no side effects." By not modifying nonlocal data (or any of a number of items considered a side effect), opportunities arise for optimizations and parallel processing.

Most functions, like square root, have no side effects. Their result is completely determined from the actual argument value and doesn't depend on anything else. Some functions, such as many random number generators, have a memory and their result depends on more than just their argument. Because of this possibility, Fortran 95 and F have a set of rules about how and when functions must be evaluated. However, if a compiler knows that a function has no side effects these rules can be relaxed and performance improved.

Forall construct

The forall construct is designed to aid in writing programs that can run on multiprocessors. The construct specifies a range of index values and a set of constraints on them which apply to the statements in the construct. A compiler is encouraged to spread the computations out among the multiprocessors; see Listing Three.

Pure functions are particularly useful in a forall construct because the processor knows that all of the instances of the functions can be executed in parallel; there is no way that evaluation of one term can effect the evaluation of any other terms.

Conclusion

F is a powerful computational language designed to be easy to learn and use. It is available on a wide variety of platforms and operating systems. For more information on F, see http://www.imagine1.com/imagine1/, which provides example code, the complete syntax, and information about several textbooks written to accompany F compilers.

Acknowledgments

We'd like to thank the following contributors to the design of the F programming language and supporters of the growing compiler technology of F software: Kevin Nomura, John Prentice, John Reid, Brian Smith, Numerical Algorithms Group Inc. (NAG), Fujitsu Ltd., Absoft Corp., Salford Ltd.

DDJ