1. Oct 21, 2012

### swartzism

I'm updating some particle physics code from Pang's An Introduction to Computational Physics. It looks like he updated F77 code to F90, but kept a lot of iffy practices in like putting all of his functions, subroutines, and modules into one file without the use of a contains.

What I'm aiming for in this thread is a discussion about GOOD vs BAD programming practices rather than personal preference. Here is his code:

Code (Text):
!!!!!!!!!!!!!!!!!!!!!!!!!!!   Program 9.1   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!                                                                       !
!                                                                       !
! (1) This computer program is written by Tao Pang in conjunction with  !
!     his book, "An Introduction to Computational Physics," published   !
!     by Cambridge University Press in 1997.                            !
!                                                                       !
! (2) No warranties, express or implied, are made for this program.     !
!                                                                       !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
MODULE CSEED
INTEGER :: ISEED
END MODULE CSEED
!
PROGRAM MCDS
!
! Integration with the direct sampling Monte Carlo scheme.  The integrand
! is f(x) = x*x.  Copyright (c) Tao Pang 1997.
!
USE CSEED
IMPLICIT NONE
INTEGER, PARAMETER :: M=1000000
INTEGER :: time,STIME,I
INTEGER, DIMENSION (9) :: T
REAL :: SUM1,SUM2,S,DS,X,F,FX,R,RANF
!
! Initial seed from the system time and forced to be odd
!
STIME = time(%REF(0))
CALL gmtime(STIME,T)
ISEED = T(6)+70*(T(5)+12*(T(4)+31*(T(3)+23*(T(2)+59*T(1)))))
IF (MOD(ISEED,2).EQ.0) ISEED = ISEED-1
!
SUM1 = 0.0
SUM2 = 0.0
DO I = 1, M
X = RANF()
SUM1 = SUM1+FX(X)
SUM2 = SUM2+FX(X)**2
END DO
S  = SUM1/M
DS = SQRT(ABS(SUM2/M-(SUM1/M)**2)/M)
WRITE(6,"(2F16.8)") S,DS
END PROGRAM MCDS
!
FUNCTION FX(X) RESULT (F)
IMPLICIT NONE
REAL :: X,F
!
F = X*X
END FUNCTION FX
!
FUNCTION RANF() RESULT (R)
!
! Uniform random number generator x(n+1) = a*x(n) mod c with
! a=7**5 and c = 2**(31)-1.  Copyright (c) Tao Pang 1997.
!
USE CSEED
IMPLICIT NONE
INTEGER :: IH,IL,IT,IA,IC,IQ,IR
DATA IA/16807/,IC/2147483647/,IQ/127773/,IR/2836/
REAL :: R
!
IH = ISEED/IQ
IL = MOD(ISEED,IQ)
IT = IA*IL-IR*IH
IF(IT.GT.0) THEN
ISEED = IT
ELSE
ISEED = IC+IT
END IF
R = ISEED/FLOAT(IC)
END FUNCTION RANF
1. I'm more of a fan of splitting up functions, modules, and subroutines into separate files and compiling with all the file names, especially when my functions, subroutines, and modules are going to be used by other main programs as well. Is this just personal preference?

2. I've never seen "function fx(x) result(f)" notation before. Is this a bad practice or am I behind on my syntax and structure?

3. What do you have to comment on the use/non-use of a contains statement?

2. Oct 22, 2012

### Staff: Mentor

Caveat: I haven't written any Fortran code for about 15 years.
For short pieces of code like the one you show, separating out the functions, subroutines, etc. into separate files adds unneeded complexity, IMO. For larger projects with modules that would serve as libraries for other applications, it is useful to split things up into multiple files, but I don't see that it's useful to put each function/sub in its own file. It would probably be better to have logically related components together.

Also, keep in mind that the main focus for Pang is computational physics, not a book to showcase good vs. bad programming style. I would imagine that Pang updated his earlier Fortran 77 code to publish a new edition, and has moved on to some other project.
This is new to me as well. I did a quick search and didn't find any other examples of it, including in code based on Fortran 90, 95, and 2003.
No comment.
As I said before, I haven't written any Fortran code for a number of years, and am more interested in C, C++, C#, and Java. It's hard for me to keep track of how much Fortran has changed since my first exposure to it, using Fortran IV on punched cards. However, I have looked at many examples of very poor code from beginners here at Physics Forums - code with incomprehensible variable names, no indentation to help the reader follow the flow of control, and all the usual things that beginners do, not knowing any better.

3. Oct 22, 2012

### Borg

I have seen a lot of similar examples from people who are working as programmers.

4. Oct 22, 2012

### Dickfore

I think the whole Fortran is a bad programming practice.

5. Oct 22, 2012

### gabbagabbahey

Yikes!

Fortran has a number of features that make it a natural choice over other languages, for some specific applications. There are a lot of well established, performance-tuned Fortran libraries out there for various types of calculations often performed in high energy particle physics, for example. Fortran's strict no-aliasing policy also naturally results in better code optimization than in higher-level languages, which makes it a great choice for doing lots of numerically intensive calculations.

6. Oct 22, 2012

### Dickfore

My point stands.

7. Oct 22, 2012

### marty1

I don't want to get into the middle of a language war, but ask yourself what those highly tuned libraries were written using.

I disagree that Fortran, while a bit archaic for most business applications, does have its place in mathematics and physics ... if only for the reason that the people who are good at mathematics and physics know it and can use it effectively without concerning themselves with the more general purpose business and finance modeled languaged we have complicated our lives with.

A hammer that everyone knows how to use is sometimes much more useful than the new fangled contraption for pounding in nails.

8. Oct 22, 2012

### D H

Staff Emeritus
Some people do that, some don't. I don't. This approach results in a huge number of files when you do a good job of modern programming and keep the vast majority of the functions very short. When some fool tries to foist this style on me in the form of coding standards, I balk, big time.

Without this, you have to say LONG_DESCRIPTIVE_FUNCTION_NAME = <some value>. What result(x) does is to let you use x as an alias for that LONG_DESCRIPTIVE_FUNCTION_NAME in setting the return value (apparently it forces you to use x).

One thing I dislike about Fortran code is that it is incredibly hard to read.
Code (Text):

! LAWYERS USE ALL CAPS FOR THE TRICKY PARTS OF CONTRACTS AND LICENSE AGREEMENTS.
! THEY DON'T DO THIS TO HIGHLIGHT THE IMPORTANCE OF THOSE CLAUSES.
! THEY DO THIS BECAUSE ALL-CAPS TEXT IS VERY HARD TO READ AND COMPREHEND.
! THEY DON'T WANT YOU TO READ OR COMPREHEND THOSE CLAUSES.
!
! Height variations in lowercase text give our eyes something to grab on to.
! Lower case text is much easier to read and comprehend than uppercase text.
!
! SO WHY ARE YOU FORTRAN PROGRAMMERS STILL USING ALL_CAPS?

9. Oct 22, 2012

### Staff: Mentor

Excellent point!

10. Oct 22, 2012

### Staff: Mentor

Here is an example taken from a recent post here at PF that could serve as the "poster child" of bad programming style.
1. Incomprehensible names: ICSEVU and NXM1 -- mean what?
2. Very short variable names: C, IC, U, S, M, IER - what do these represent?
3. Old style DO loops with line numbers: DO 40 K=1,M
4. No indentation whatsoever makes it difficult to follow flow of control
5. Very little whitespace: subroutine ICSEVU (X,Y,NX,C,IC,U,S,M,IER)
6. No explanation of what the subroutine does and what parameters are needed.
7. Mostly all caps - difficult to read

Code (Text):

subroutine ICSEVU (X,Y,NX,C,IC,U,S,M,IER)
INTEGER NX,IC,M,IER
real*8 X(NX),Y(NX),C(IC,3),U(M),S(M)
INTEGER I,JER,KER,NXM1,K
real*8 D,DD,ZERO
DATA I/1/,ZERO/0.0d0/
C FIRST EXECUTABLE STATEMENT
JER = 0
KER = 0
IF (M .LE. 0) GO TO 9005
NXM1 = NX-1
IF (I .GT. NXM1) I = 1
C EVALUATE SPLINE AT M POINTS
DO 40 K=1,M
C FIND THE PROPER INTERVAL
D = U(K)-X(I)
IF (D) 5,25,15
5 IF (I .EQ. 1) GO TO 30
I = I-1
D = U(K)-X(I)
IF (D) 5,25,20
10 I = I+1
D = DD
15 IF (I .GE. NX) GO TO 35
DD = U(K)-X(I+1)
IF (DD .GE. ZERO) GO TO 10
IF (D .EQ. ZERO) GO TO 25
C PERFORM EVALUATION
20 S(K) = ((C(I,3)*D+C(I,2))*D+C(I,1))*D+Y(I)
GO TO 40
25 S(K) = Y(I)
GO TO 40
C WARNING - U(I) .LT. X(1)
30 JER = 33
GO TO 20
C IF U(I) .GT. X(NX) - WARNING
35 IF (DD .GT. ZERO) KER = 34
D = U(K)-X(NXM1)
I = NXM1
GO TO 20
40 CONTINUE
IER = MAX0(JER,KER)
9000 CONTINUE
if(jer.gt.0) then
write(6,29666) jer
29666 format(1x,'err.mess. from ICSEVU jer=',i4)
end if
if(ker.gt.0) then
write(6,29777) ker
29777 format(1x,'err.mess. from ICSEVU ker=',i4)
end if
9005 RETURN
END

11. Oct 22, 2012

### D H

Staff Emeritus
You missed some.
8. Unstructured code / GO TO.
9. Meaningless comments. Only one comment is what I would call "meaningful".
10. Silly variables such as ZERO. I treat the "no magic numbers" rule as guideline rather than a rule. When carried to its extreme form, the "no magic numbers" rule leads to things like ZERO when 0.0 is clearer.
11. Comparing a floating point number by equality rather than testing for within some small epsilon.

Last edited: Oct 22, 2012
12. Oct 22, 2012

### swartzism

The long descriptive function name fx(x) result(f) can simply be changed to "real function fx(x)" with the internal variable f being changed to fx. It eliminates an unneeded variable and keeps the simplicity. I can see how it works in some situations though. Any actual functionality benefit? Increased speed?

The all caps deal was Pang. I don't like to yell at the future programmer by using all caps.

Why is do-continue a bad programming practice? Besides the obvious bad examples you've used.

And I'm not even going to touch "fortran sucks" with a 10 foot pole. Go work in a supercomputer center, NASA's biological computer science division, or any oceanography/atmospheric modeling government contractor and report back.

13. Oct 22, 2012

### D H

Staff Emeritus
The key benefit is that it enables recursion. Before Fortran 90, Fortran didn't support recursion. You had to roll your own. Try writing Ackermann's function in Fortran IV.

It's not needed; Fortran is case-insensitive. However, ALL CAPS it is pretty common in Fortran. Fortran started in the teletype era. ALLCAPS was all there was. "That's the only way we could do it" morphed into "That's the way we always do it" which in turn morphed into "That's the right way to do it." That is not the right way to do it (it makes the code virtually unreadable), but try to tell some Fortran programmers that.

Fortran 90 (twenty years late, but eh) introduced structured programming constructs to the language. Use them. You shouldn't need labels except for very rare exceptions.

There are lots of places that have turned from Fortran to other languages, and that trend is continuing. Projects switch from Fortran to anything but Fortran soon after the intransigent, "C++? Over my dead body!" project manager retires. One reason is that Fortran is so very far behind the times. 30+ years late in introducing recursion, 20+ years late in introducing structured programming concepts, 20+ years late in introducing object oriented concepts (and good luck finding a Fortran 2003 compiler). The language has earned a self-imposed and well-deserved black eye.

Another reason for this switch is that Fortran is no longer a commodity language. It hasn't been a commodity language for a long time. This makes it hard to find good Fortran programmers; it's hard to find Fortran programmers period.

Fortran does do a lot of things right. There are still times when I wonder why we all switched from Fortran to C and then C++. Usually it's when I have to call pow (or more likely, my own version which does it right for small constant integer powers) instead of using ** as an operator, with the compiler doing it the right way. There's no convincing the C/C++ powers that be that pow is just wrong, wrong, wrong when it comes to scientific programming.

As a counter to that "Fortran is behind the times" argument, C99 finally introduced a keyword that lets me tell the compiler that it can assume that the arguments to a function do follow strict aliasing. Does the compiler check if calls to that function are consistent with the strict aliasing? Of course not. Calling such a function incorrectly is "undefined behavior". That huge amount of undefined behavior in C, and boatloads more of it in C++, is another thing that occasionally makes me question the wisdom of switching from Fortran.

14. Oct 22, 2012

### AlephZero

What D.H says is troe for Ansi standard Fortran.

But it ignores the fact that there was a de facto standard that was supported by every "serious" Fortran compiler, and used by most "serious" Fortran scinentic programmers. Those extensions did support recursion, dynamically allocated variables, user defined data types, and more.

Of course, being "only" a de facto standard, it wasn't "perfect". But neither are most official standards.

IMO Fortran 90/95 adds little to that, and what it does add is offset by the baroque syntax. Does somebody get commission for every non-value-added ":" typed in the new syntax, I wonder?

15. Oct 22, 2012

### marty1

Well, I brushed up a little bit on some of my ancient Fortran and what I see in Fortran after several decades being a professional c++ deveoper is that what is a best practice in one context is not always definitively best. There are some merits to monolithic, self-contained programs built for a specific purpose. Fortran programs are not necessarily written by programmers whose sole purpose in life is to write programs. Fortran is a tool used to programmatically express formulas, simulations, control devices, etc. You could reorganize a fortran program but it is only reorganization. All the promises of reuse are even rarely realized in c++ unless it's a large enough piece to be a library on its own. I would recommend against contains for contains sake because unless what you extract can stand on it own it's not really worth the complexity or keeping track of all the pieces. I have seen my share of over-organization and even contributed to it myself. It seems to me that the goal of the Fortran programmer is not abstraction but purely concrete expressions of real things.

16. Oct 24, 2012

### marty1

Regarding the comment a few posts back about pow vs. **, this is an unfortunate grammatical situation. * is used for multiplication and for dereferencing the value pointed to by a pointer. As a result a**b would be a times the value pointed to by b or the contextually ambiguous dereferencing of a pointer to a pointer. It is just an unfortunate linguistic corner they were backed into with a limited number of operator symbols.

Beyond that it is a constant reminder that you are not performing a simple operation like +-*/ all directly implemented by single cpu instructions.

Last edited: Oct 24, 2012
17. Oct 24, 2012

### D H

Staff Emeritus
I've seen that argument, and it is bogus (IMHO). It's bogus because x**2 and x**0.5 are invalid syntax. The former can be made valid via (for example) x**(char*)2, but now you have something of the form rvalue**pointer. The solution is simple: make a**b have dual meaning. It means exponentiation if b is of a numeric type, multiplication by a dereferenced pointer if b is of a type that supports dereferencing. It's not as if C and C++ aren't already chock full of overloaded terms. The static keyword, for example. What's wrong with one more?

That too is bogus. The argument falls to pieces in C++ where I can overload operator+. It even falls to pieces in C because the time it takes to do an extended precision divide is many, many times the amount of time it takes to do an integer addition. Fortran is even more concerned than is C with regard to speed of numerical operations, and yet this distinction is not an issue in Fortran.

Ask that "over my dead body" manager to whom I earlier referred why he is dead set against C or C++. The lack of an exponentiation operator will inevitably be one of three reasons why C/C++ are so bad for numerical programming. The poor way in which C/C++ treats vectors and matrices will be another reason, and that C and C++ not only allow but encourage aliasing will be yet another reason.

18. Oct 24, 2012

### I like Serena

Not true.
Any ambiguity with ** would be resolved by the lexer (if you intend a * *b, please use spaces).
This is similar to for instance ++ or >>.

Note that >> and :: do have unfortunate and unexpected lexical side effects when used in a template declaration.

19. Oct 24, 2012

### D H

Staff Emeritus
There's lots of legacy code out there where people eschew spaces. Apparently touching the space bar consumes some precious rare resource. Some programmers are very concerned with over-consuming this resource and touch the space bar very sparingly. I've seen 120+ character long lines of C++ code with nary a space after the initial indent.

20. Oct 24, 2012

### I like Serena

I take it they use one space as an indent? ;)

If you're wondering when this happens, please try:
Code (Text):
#include <vector>
::std::vector<::std::vector<int>> matrix;