Packs -- the classic Fortran libraries

All the more the power to you. Especially since you’re leading the “pack” and putting in the effort.

To each their own is likely a better position with GOTOs only to avoid endless debates, even as seeing them as “evil” and avoiding them altogether is a good position to strive toward.

I presume you are doing test-driven development. Having an exhaustive test suite and adhering strictly toward validation of results with such a suite with suitable tolerances toward differences will take you a long way.

If you rid the code of all GOTOs along the way, all the more the better!

Hmmm, I used to dislike the now deprecated way people used to (sort of) do that, where there
were a lot of assign statements right after the variable declarations, like this with lots of code between the assigns and goto, of course …

integer :: ERROR
assign 9999 to ERROR
!! lots of code
goto ERROR
!! lots of code
9999 continue ! ERROR
end 

But I think I would like it fully implemented as described above; would have to think about it.
Not too long ago I had to change a code to make it portable where instead of the ASSIGN in the above example, they had “INTEGER,PARAMETER :: ERROR=9999” and it worked; I think it was an ifort extension (or compiler bug, depending on your viewpoint :slight_smile: )

Metcalf, Reid, and Cohen in Modern Fortran Explained say this about go to:

4.6 The go to statement
Just occasionally, especially when dealing with error conditions, the control constructs that
we have described may be inadequate for the programmer’s needs. The remedy is to use the
most disputed statement in programming languages – the go to statement – to branch to
another statement. It is generally accepted that it is difficult to understand a program which
is interrupted by many branches, especially if there is a large number of backward branches
– those returning control to a statement preceding the branch itself.

1 Like

Yes, I think if the alphanumeric address was allowed, it should only allow going forward, not backward. It was ifort, this actually works in ifort; was definitely non-standard in the past; I think it still is …

program testit

integer,parameter :: ERROR=9999
write(*,*)'got here A'
goto ERROR
write(*,*)'got here B'
stop
9999 continue ! ERROR
write(*,*)'got here C'
end program testit

This can be simpler, and involve fewer changes to existing code written in this style. But if I’m seriously trying to make some code easier to understand and maintain I often end up with a different control flow style which doesn’t necessarily make this the ideal structure. I’m not saying it’s inherently bad, but it is still often possible to redesign the code/algorithm to avoid it if desired. This is the one usage of goto I would consider “acceptable” as a matter of existing practice, but still not necessarily desirable. If this is a style and convention you follow, I won’t find your code hard to understand, it’s just not my preference.

See also my (somewhat cheeky) post from 2016: GOTO Still Considered Harmful. :slight_smile:

2 Likes

+1

More then GOTOs or other syntactical elements, I’m more worried about COMMONs or other global variables that prevent the code to be called concurrently.

In some old code, I’m also worried about the assumed initialization (typically zero), or the assumption that a variable retain its value between different call to the same routine.

Typically I compile them with gfortran -Wall and then look for any uninitialized variable, but then I’m wondering what would be the correct initialization of the variable (typically zero), or if I’m ruining something without knowing.

By the way, I prefer generally pack code without global variables, as for example, minpack or the dierckx routines, and put a bit of modern interface around them.

2 Likes

Note that you can get a free plusFORT licence for use in updating public domain codes such as these. plusFORT can do the sort of spaghetti unscrambling described above but can also perform other modernisations, such as adding declarations to allow use of IMPLICIT NONE, converting declarations to Fortran 95 style and adding intents for dummy arguments. It also analyses call structures and data usage and produces reports which help modularize the code.

I’d also be happy to spend some time working on this myself. Although I’ve used a few of these packages in the past, I’m not a current user. If anyone can suggest somewhere to start, I’ll take a look.

You can request a licence using the contact form at www.fortran.uk, but because I will be completely off-grid next week, you won’t currently get a prompt reply. In the short term, please refer to the following post to get a free time-limited licence for plusFORT.

1 Like

The “spag” program that’s part of plusFORT from Polyhedron Software can convert from fixed to free form. It can also structure a program, usually eliminating most GOTO statements.

Polyhedron offers a free limited-time license for non-commercial use.

1 Like

The Lapack BLAS use assumed-size array arguments, for example

      SUBROUTINE DGEMM(TRANSA,TRANSB,M,N,K,ALPHA,A,LDA,B,LDB,BETA,C,LDC)
*     .. Scalar Arguments ..
      DOUBLE PRECISION ALPHA,BETA
      INTEGER K,LDA,LDB,LDC,M,N
      CHARACTER TRANSA,TRANSB
*     ..
*     .. Array Arguments ..
      DOUBLE PRECISION A(LDA,*),B(LDB,*),C(LDC,*)
*     ..
*
*  Purpose
*  =======
*
*  DGEMM  performs one of the matrix-matrix operations
*
*     C := alpha*op( A )*op( B ) + beta*C,

Does modernizing mean using assumed-shape arrays, or are explicit-shape arrays acceptable in some cases, when performance is paramount? (This assumes that there is a performance difference between assumed-shape and explicit-shape arrays.) Code with explicit-shape arrays such as

subroutine foo(n1,n2,mat)
integer, intent(in) :: n1,n2
real, intent(in) :: mat(n1,n2)
...

is not hard to read. I think the main objection is that the actual argument for n1, n2, mat may not be consistent in the calling code.

They can also clutter the API - think of a midly complicated LAPACK routine where all matrices are associated with two or more such arguments besides the matrix itself.

Unfortunately, it is not possible to replace assumed-size arrays with assumed-shape arrays in just the client code, because the BLAS routines will continue to exist with assumed-size dummy array arguments, which in general will not be compatible with actual arguments that are assumed-shape.
As of now, you can use an interface layer such as BLAS95 (and, similarly, Lapack95), which allows you to write:

call gemm(a, b, c [,transa][,transb] [,alpha][,beta])

and requires that you (i) provide an interface in the client code, and (ii) link with an additional library such as libblas95.so or BLAS95.LIB.
The use of such interface libraries requires that one have the corresponding *.mod files available for each compiler that is used.