Silverfrost Forums

Welcome to our forums

Structured programming newbie! could someone please advise?

1 Oct 2007 5:57 #2278

Hello Folks,

I shocked some of you last week when revealing that I had been writing my fortran programs (after being advised to do so by my superviser!) in an unstructured way - one long list of instructions. I'd like to thank those that offered advice - advice which I've followed and have drastically improved my code.

I completely understand why structured code is much easier to debug and understand than the unstructured form I was using. I have recently been swotting up on sub-program units etc and have been re-writing my programs using lots of modules, subroutines and functions as some of you kindly advised.

I have a couple of brief questions - I was hoping that one of the experts could provide some advice.

  1. I understand that modules are a way to provide global access to program variables. Does this mean then that I should simply declare ALL of my variables in a module so that each procedure can access them without me specifying long lists of arguments?

  2. My program performs a number of numerical experiments. These experiments often require different sized arrays to be used. The program cycles through each experiment, running each one until completion then moves on to the next one. At the moment I am using allocatable arrays to facilitate this. The program reads in the correct array sizes - allocates & uses the arrays and then de-allocates them prior to starting the next experiment. I wonder if there is perhaps a more efficient way to do this?

I would really appreciate some advice on these matters. My code is working well at the moment but I'm always eager to learn ways to improve it. I now have two versions, a nice structured one for me and an unstructured one for my boss!

Many thanks, B

2 Oct 2007 6:49 #2280

Hi,

A couple notes about subroutines may help sharpen your view of them.

In general, you should only make global those variables that need to be. One major advantage of subroutines is that all the local variables stay local. In the program method preferred by your boss, once you use a variable name, you have to be responsible for it for the entirety of your program. This is much easier to do in a smaller program unit like a subroutine.

Basically, if you make all your variables global, you're a long way towards making the program like your boss seems to like them.

Secondly, it is often useful to SAVE the variables in your subroutine; that is, they will still have the values you left them with when you return. This can have many uses, for example, knowing if this is the first time through the subroutine.

One question to consider on the issue of allocating and de-allocating arrays. Are you so pressed for memory that you care?

2 Oct 2007 8:41 #2283

Hi Technophobe

on the whole:

local variable good global variable bad

before the howls start I use global variables when appropriate

appropriate means they should be truly global

ie have relevance for the whole program.

with regard to allocating/deallocating I presume that you have found that you can pass arrays as parameters to subroutine eg

!-------------------------------------------------!

program testapp implicit none real vector1(3),vector2(3) integer i

vector1 = 1.0

call vectorsub(vector1,vector2)

do i=1,3 write(,) vector1(i),vector2(i) end do

end program

!--------------------------------------------------------!

subroutine vectorsub(vector1,vector2) implicit none real vector1(3),vector2(3) vector2 = vector1 +1.0

end subroutine

!--------------------------------------------------------------!

paremeterized subroutines is one of the big benefits of subroutines since you can abstract common tasks with different parameters thus reducing the amount of code you need to type!

btw

implicit none

mean you have defined all your variables and the compiler will fall over if you have mistyped something good practice !

anyway keep the questions coming

Carl

2 Oct 2007 9:05 #2284

I understand that modules are a way to provide global access to program variables.

I too have heard people say this, or words to that effect, about modules. Personally, I think that is the wrong way of looking at them. Common blocks are a way to provide global access to variables. Modules, on the other hand, are a way of hiding entities, not just variables, from the rest of the program.

Modules can contain data and procedures, of course. As an example, consider implementing a data structure and procedures for accessing and manipulating that data structure. A module allows the whole implementation to be bundled together and to hide (make PRIVATE) all the esoteric details of the implementation that are not needed by a user of the data structure resulting in a cleaner and more secure overall implementation.

Keith

3 Oct 2007 1:59 #2293

Hi Guys, First let me thank you all for your advice - I'm taking it on board and trying to improve my programming skills. I've been working through some of sections of a very good Fortran textbook but it's always good to get advice from people who actually use Fortran themselves.

I have made a module at the start of my program that contains all the global variables and another module that contains the procedures. In the past I always added the procedures at the bottom of the code, after the main program unit. I have read that putting subroutines into modules means that the interface between the subroutines and the calling program become explicit - and that the compiler will let me know if I mess up when calling the subroutine.

I was wondering if I actually needed to include the modules at the top of the code. I realise that this seems like a very trivial point but with the subroutines, declaration statements etc at the top of the code the main program is right at the bottom I have to continually scroll upwards and downwards between the two distant parts of the code while I'm checking for errors etc. My code isn't that big but I imagine that for very large codes this must be a real pain.

I was also wondering about the global/local variable concept. I realise from your comments that global variables and local variables have distinct uses, local variables should be used wherever possible - I have taken this advice on board in my work. I was wondering though whether there are any performance issues related to the use of global/local variables? I understand that a variable local to a subroutine is invisible outside that subroutine but does this offer a saving in memory or performance over making the local variable a global one? I'm wondering if declaring all of the variables globally requires more computer memory or causes performance issues?

Many thanks, Bren

3 Oct 2007 2:48 #2294

I was wondering if I actually needed to include the modules at the top of the code

It certainly is not a trivial point. What I do is put each module in its own separate source code file. For example, if you have a module named ‘MyStack’ put it in a file named ‘MyStack.f90’. Compile it separately with a command such as,

FTN95 /IMPLICIT_NONE /CHECKMATE /ERRORLOG MYSTACK.F90

This will produce two files, MyStack.obj and MyStack.mod. Then when you compile your main program, link the mystack.obj into the program.

I don’t know if you are using the command line (as I do) or the Plato environment. You may find it a bit of hassle to set up separate compilation initially but believe me, I cannot imagine handling a project of any complexity without using it.

As for your thoughts regarding performance issues related to the use of global/local variables, I would say don’t worry about that. Concentrate instead on structuring the program so it is easily understood and can be maintained.

3 Oct 2007 3:01 #2295

Thanks Keith,

I'm using the Plato environment on a windows XP system. I'm not very familiar with the command prompt aspect of XP but will soon be using Sabayon Linux for most of my work; I will get my head around the linux command prompts when the time comes.

I really appreciate your advice. To be honest I hadn't considered making my subroutines a seperate entity from the main program. That would make my life a lot easier and would make the code much easier to read. I'll have a look through the plato help files and try to work out how to do that later this evening.

Cheers, Bren

4 Oct 2007 8:55 #2302

I just though I would add my support to both points

have multiple files for multiple subroutines this means you can if have subroutines in lots of different projects if appropriate without doing unnessary cut and paste.

also I think the performance comments is really important occassionally you see bits of code that have been 'optimised' that are totally unreadable and total time saving is probably a microsecond or something of that order - and might actually make the code run slower since the optimisation probably wasn't banchmarked properly in the first place someone just though this will be quicker without bothering to check.

so here is my check list before optimising code

  1. do you really care about the run time being this long?

  2. do you think that you can make a significant difference which will now be acceptable? 60 minute down to 40 minutes is a big time saving but you still have to go away and come back!

  3. Analyse the code, what is the slowest part? Can you significantly optimise this bit? shaving a 5s off a data read is not going to help with 40 minute iterative procedure!

  4. having done 1 to 3 are you still sure its worth changing the code?

  5. if so make a back up of working, perfectly fine, slow code

  6. try and oprimise the slow bit of code.

  7. do some tests , does it still work ? is it faster?

  8. make mental note was that code change worth the effort for x minutes run time write the answer in new optimised code as a comment and also a similar comment in the original code.

sometimes the answer to question 8 is yes definitely, I have seen commercial Fortran programs run times decrease from 60 minutes dwon to 1 minute from release n to relase n+1, however most of the time the answer is no it wasn't especially as in 3 years time with a new faster computer your huge x minute imporovement has become a not so impressive x/2 improvement etc.

anyway as you have probably guessed I like readable code!

Carl

5 Oct 2007 8:20 #2316

Hi,

You seemed worried a lot about memory and speed. Those are the kind of questions more common in the 1960s or associated with big crunching programs (like a couple I have that take days to run). Is this an issue with your boss or are you writing programs w/ realtime constraints or are your programs taking a long time compared to the time people have to wait for the output or are you running out of memory? If not, then forget these kinds of issues and focus on understandable code.

I would like to mention one issue in which I am in the minority. I never use implicit none. This leads to long lists of declarations, obfuscating the important ones. I don't have any trouble in remembering that ijklmn are first letters for integers and everything else is real. Not the hardest part of programming. Long lines of declarations start to look like Cobol programming and the code starts to exceed the one page criterion.

Finally, it may not be too early to note that one can go overboard in making lots of functions and subroutines. I've seen programmers turn a ten line program into three highly interactive routines each calling the others. Easy to understand code was turned into a morass that required lots of flipping back and forth to decipher. Another problem is when you've constructed so many functions and subroutines that you can't remember what you've got, you find yourself rewriting them.

Comments: while it is silly to write comments that say things that just paraphrase the code (e.g., now we add a to b), any time you think you may have some future issue about some section/line of code, you will; so, write a useful comment. Write it not like you're writing as the clever person who just figured out how to do it but as though you're writing for someone to whom the code is new...that is how you'll feel about it when you try to read it a few weeks from now.

My experience over 40 years of programming is that very little code is reused. Even the easiest subroutine is much less general than you think. If you start generalizing code to be more general than you need you're probably wasting your time and you're probably making it harder to understand.

and, by now, you know that making it easy to understand is the most important goal after getting it right.

5 Oct 2007 10:39 #2317

My guess is that anyone who has taught Fortran to beginners would strongly advise the use of IMPLICIT NONE, at least during development.

You can follow the rules and remove the declarations later if you prefer.

5 Oct 2007 8:39 #2321

I'm sure that Paul's guess is almost right. I know I have not taught it and I know of others who do not as well but, again, I'm sure that we're in a small minority. It also seems true that many beginners do make the implicit typing error which, by dint of the fact that some compilers can make it difficult to track down, serves as a pretty good lesson. My belief is that most spend less time learning this lesson than typing every darn temporary variable.

It is not worth taking up much more of the forum's space on this issue. I think the more important point is that the programming *craft *should permit its craftspersons to program in styles which best suit their needs and capabilities. Style 'rules' have been around forever and many are important suggestions. But you must consider how they fit you first. Also, how they fit the problem. The most common failing in programming is a failure to select the right language for the problem and the right style. On major projects, I have found that choosing the right style in both design and implementation is essential; multi-million dollar programs so difficult that only one style would be successful. And there are famous projects of the same size that have failed for reason of choosing the current programming fad as opposed to carefully considering the problem at hand. Even for small projects, a few minutes of reflection on what style would be most appropriate will probably save many times that many minutes in the future.

(a funny example of this was a major project I was on recently in which the customer demanded that extremely long, self-descriptive variable names be used. So long, in fact, that if one used standard structured programming indentation, arithmetic code usually took many continuation lines making it -gasp!- pretty unreadable. I solved the problem by simply inverting the indentation order so that inside logic, which usually where the arithmetic occurs, had the full line. Much more readable.)

The first style book in my life was Kernighan & Plauger, The Elements of Programming Style, 1974, which was modelled after Strunk and White's Elements of Style. I see that a second edition is still available. A good thing about that book is that it is focussed on Fortran. This is one of the seminal books on programming style, doing much to introduce structured programming. In fact, considering there are an infinite number of style questions that can fill up this forum, I strongly suggest you invest in a copy. Glancing through it now, I see how much it influenced me (and how strong an effect it still has today on modern language rules, fads, and styles) and, through experience, how some of their suggestions I put aside.

Unfortunately, much of what they considered style is now carved in stone in many programming languages. Unfortunately, this behavior is starting to creep into the Fortran standards as well. I think this behavior is a symptom of folks whose major concern is the language, rather than the solving of problems with the tool of programming.

6 Oct 2007 5:38 #2323

Just to let everyone know, I'm a member of weaverwb's minority, I never use 'implicit none' either, for exactly the same reason's he quotes. Although I have read on many occasions to the contrary. I just stick to the default integer and real names (as that's how I was taught) and have never experienced any difficulty.

6 Oct 2007 8:56 #2324

To Weaverwb and JohnHorspool

I’m curious to know if either/both of you have done mainly Fortran programming with very little work in other languages. Please don’t misunderstand my motive for asking this. I’m not trying to imply anything derogatory. I’m just curious to know.

I’m one of the fans of IMPLICIT NONE, but I’m wondering if I picked up my liking for it from using other languages.

Keith

6 Oct 2007 9:33 #2325

Keith,

Yes you are spot on. I've used Fortran for 30+ years. I last used another language (Basic) in 1980.

Regards, John

8 Oct 2007 12:15 #2326

Hello guys,

I've noticed that a couple of posts have talked about declaration statements as if they're a bad thing. I always use the IMPLICIT NONE command and tend to write a long list of variable declaration statements (usually with a comment beside them to indicate what the variable is/what it's used for). I find that this helps me understand my code when I look at it months later.

From some of the posts in this topic some of us prefer not to have lists of declaration statements but I'm unsure why this would be the case. Why are lengthy declaration statements a nuisance?

One more thing I'd like to ask about programming style: I have been told by a colleague that any piece of code longer than about a page should be made into a subroutine. I'm not sure whether this is some sort of rule of thumb concerning programming style or whether this offers some technical advantage. I have been experimenting with sub-programming units recently and have decided that the best way to write my code is to break it up into logical sections. The main program performs only a few calculations and calls the subroutines which do the useful stuff. The subroutines themselves differ in size from about 50-300 lines. The larger subroutines are required to perform rather complicated calculations and I see no advantage in breaking them up into separate subroutines. My colleague has many years of programming experience behind him and I was wondering whether his advice is merely a guideline or whether short subroutines offer some advantage in efficiency?

Regards, Bren

8 Oct 2007 7:32 #2327

Hi all,

Programming languages: FORTRAN, various kinds of Basic (best for quick and dirty programs), Aion 7 (an expert system language); occasional C, C++ (I don't like assembly languages, however they're renamed), java rarely.

In ancient history, assembly, algol and pascal. The later two, as well as Aion, insist on declaration. It is actually from those languages that insisted on typing that drove me away from it.

The declaration statements and the rule-of-thumb about one page code are tied together to some degree. For a lot of us, the more pages you have to juggle to understand a procedure, the harder it is. Lengthy declarations extend the pages; they obfuscate important declarations by surrounding them with a forest; and, if you don't have some default typing scheme, make you flip back and forth between the code and the declarations. Kinda like trying to read a book when you have to keep flipping back to the glossary or dictionary. My declarations are usually saved for important variables that, even though they follow the implicit typing scheme, need commenting for clear understanding of the code.

Certainly there is no point to artificially break up code that is clear as it is. Sometimes one has a very sequential method that trudges on with little branching or logical complexity. But even if it sequential, it often improves the readability to intermix comments and calls to subroutines. This way one has an upper-level program: e.g., First we're going to do a setup for the program; then we do step a, which calculates the widgets; then we do step b which sorts the widgets; then, depending on b, we either do c, invert the widgets or d, calculate an adjusted set of widgets, etc. Each step has one or a few calls to some well-named/commented subprograms.

I often write programs of thousands or tens of thousands of lines of code. A current project I'm working on --spectroscopic data reduction -- currently is about half done and contains 3360 lines of code (not counting comments, blank lines, etc., spread across 128 subprograms. That is about 25 lines of code per subprogram and six lines of declarations. There are two or three subprograms that spread over two pages or more and those are the ones I have the least faith in (although they seem to be working). They are complex because I don't understand them fully enough to make them shorter. Like Mark Twain said at the end of a letter --' I'm sorry but I didn't have the time to make this shorter'--

A second, more mature program, having to do with non-local thermodynamic equilibrium radiative transfer in turbulent plasmas, currently has about 5000 lines of code in only 26 subprograms. These are way too long and are really difficult to debug or to add new physics to. My only excuse is that some routines grew as we learned more about the physics. I've seriously considered taking a month or so and rewriting it into smaller, better organized routines. These also have about one line of declaration to five lines of code.

I would say that other fields I've written software for, such as ops analysis, dp, huge rule-based programs that compute benefits for millions of people, pretty much conform to these kinds of numbers.

I'd say the one page rule of thumb is primarily a human limitation to what one can hold completely in one's head at one time. Beyond that, you're probably thinking of it at multiple levels...various levels of summary or outline. It seems, for many of us, to let the code reflect that mental organization.

You keep mentioning efficiency. I've written lots of real-time code, concurrent code, and code that must run tens of thousands of times an hour. My approach, in the 'modern' computer era, has always been to insist on clarity of code first. If the hardware can't keep up, buy more hardware. It is almost always cheaper that software that cannot be maintained or passed on. I have a counter example to this but it is much more complex to discuss and would extend this lengthy post to an intolerable length.

8 Oct 2007 10:18 #2328

Quoted from weaverwb I have a counter example to this but it is much more complex to discuss and would extend this lengthy post to an intolerable length.

Would that be a computer program to prove Fermat's Last Theorem, then? :lol:

Andy

8 Oct 2007 3:24 #2330

Hi Weaverweb,

I keep mentioning efficiency because for the problem I'm trying to solve this is quite a serious issue. I'm trying to develop a code that will solve transonic flow around a moving airfoil. The code is to be used on a laptop computer so the option of buying better hardware isn't an option.

The code uses an ADI scheme which sweeps through the domain and solves my equations. I want to strike a good balance between grid density and efficiency. If I can speed up the calculations slightly then I can introduce more points into my grid and improve the accuracy of the solution.

I have had several codes in the past that, by tweaking a few things here and there, have gone from 2-3 hours runtime down to 20-ish minutes. These codes had been written inefficiently (by me!) and through learning more about programming I made them more efficient and managed to greatly reduce the runtime. If I could even save a tenth of a second in each sweep then it'd be a good thing.

besides - I ask my boss: 'you can have this done either fast or you can have it done right'

he says: 'both' 😃 Cheers, Bren

8 Oct 2007 3:54 #2331

The declaration statements and the rule-of-thumb about one page code are tied together to some degree

I tend to agree that declaration statements and the rule-of-thumb about one page code are tied together to some degree but for a totally different reason.

Up front, let me say I use IMPLICIT NONE, so I declare everything. Now, when I’m writing a subroutine and the declarations are getting lengthy I start wondering if I really do need all these entities in scope at the same time. Far from regarding declarations as a nuisance I regard them as having many positive benefits such as indicating the complexity of a subroutine and prompting me to perhaps rationalise the code.

I also like to make a distinction between dummy arguments and local entities. I regard the number and type of the arguments to be an indicator of the complexity of calling that subroutine: quite distinct from, but related to, the internal complexity. I tend to have two declaration blocks at the head of my subroutines. In the first block I declare all the (dummy) arguments to the subroutine devoting one line to each argument (with a comment tagged on the end). In the second block I declare all the local entities often placing several per line.

  INTEGER, INTENT(IN)           :: dummyArg1     !Comment 1
  INTEGER, INTENT(IN)           :: dummyArg2     !Comment 2
  REAL(KIND=single), INTENT(IN) :: dummyArg3     !Comment 3

  INTEGER           :: int1, int2, int3
  REAL(KIND=single) :: real1, real2, real3

Lengthy declarations extend the pages; they obfuscate important declarations by surrounding them with a forest …

I really don’t see why complete declarations obfuscate important declarations. If you don’t want the important declarations to be surrounding by a forest, put them on a single line. This then gives you the opportunity to tag a comment onto the end of the line, which would otherwise have to occupy an extra line anyway.

12 Oct 2007 8:58 #2353

Would that be a computer program to prove Fermat's Last Theorem, then?

Ha! I deserved that!(':lol:')

No, I just have some code that would take about a year to run completely and discussions of it drags in design methodologies and such..

Our famous boss seems to have the standard boss answers from the 1960s. I assume you're using the profiling tool; another advantage to having smaller routines: they make locating the inefficient parts easier. Getting an order of magnitude improvement by tweaking a few things is pretty astonishing. I would hope that these experiences have led to a programming style that could never have such improvements.

As per using implicit none as an algorithm design aid during programming, a true computer weenie would say you should do the design before you start the coding but I agree that in the real world, problems are often too complex to properly understand before you actually try to code them.

I've never said that folks shouldn't use implicit none if it helps them; what burns me are folks who proclaim that everyone should work this way and worse, languages that insist on it. I note occasional hints that some folks think that Fortran should do away with implicit typing. Some of us find the typing of every variable little more than an annoying waste of time. A good language should be supportive of a wide range of programming styles, supporting our individual, idiosyncratic strengths and weaknesses in solving problems. For some of us, remembering ijklmn is no problem and we find no other use in typing each and every variable.

OBTW, using one line per variable just leads to long, Cobol-style front ends, which are also great for obfuscating the important variables. A page of declarations, for me, is guaranteed to hide any important declaration. I've even been known to put 'standardized' local variables in an include to further keep things as clean looking as possible. This way I know that each of the visible, declared variables is important.

Please login to reply.