Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

help on some design on processing a file

858 views
Skip to first unread message

Pascal

unread,
Oct 7, 2016, 10:46:05 AM10/7/16
to
Hi,

I am processing a file which have about a hundred keywords. Each keyword
would be processed by a particular subroutine.

I am trying to write some code where I could call a subroutine depending
on the content of a variable. Something like this:
call process(keyword, argument)
Where `keyword` would be called with the argument `argument`.

Is there any way to do something like this?

I could do:
SELECT CASE (keyword)
CASE ('keyword1')
call keyword1(argument)
CASE ('keyword2')
call keyword2(argument)
CASE DEFAULT
call error('does not exist')
END SELECT

But that would mean modifying the select case when adding a new keyword.
I am wondering if there is an easier way.

Pascal

vladim...@gmail.com

unread,
Oct 7, 2016, 1:06:36 PM10/7/16
to
> But that would mean modifying the select case when adding a new keyword.
> I am wondering if there is an easier way.

Depends what you call easier, but to have more flexibility you can use a hashtable library and procedure pointers pointing to your subroutines.

Louis Krupp

unread,
Oct 7, 2016, 4:04:24 PM10/7/16
to
On Fri, 7 Oct 2016 15:46:03 +0100, Pascal <pasc...@parois.net>
wrote:
It depends on what you mean by "easier."

If you are (or if you want to be) familiar with dynamically loaded
libraries, you could create a function for each keyword and load it
dynamically and then call it when that keyword appears. You might
have to write a C interface.

If your main program does very little besides calling the appropriate
subroutine for each keyword it sees, you could put each of those
subroutines in its own program and have your main program (which you
can now call a "driver") use execute_command_line() to run the
appropriate program. I believe this is a Fortran 2008 feature, so
your compiler might or might not have it. If it doesn't, there could
be more C code in your future.

As an alternative to that, you could write the main program in a
scripting language like Perl or Python and have it read the input file
and run the appropriate programs, passing each one any data it needs.

Have fun.

Louis

Terence

unread,
Oct 7, 2016, 5:43:27 PM10/7/16
to

"Pascal" wrote
>I am processing a file which have about a hundred keywords. Each keyword
>would be processed by a particular subroutine.

>I am trying to write some code where I could call a subroutine depending on
>the content of a variable. Something like this:
> call process(keyword, argument)
> Where `keyword` would be called with the argument `argument`.

>Is there any way to do something like this?
(snipped)
>But that would mean modifying the select case when adding a new keyword. I
>am wondering if there is an easier way.
Pascal

You must have a list of your keywords either inside or outside your program.
So, it is best if OUTSIDE, since this allows the use of ANY USER language by
just changing the file supplied.
This text file is first read, line by line, and best if each keyword is
preceded by its unique number, since this allows easy removal of any
unwanted words in the future, without changing the program.
So there are two matrices, one has the series of ID numbers and the other
the keywords matching those numbers both in the same index order.
If the external keyword list is arranged in the most probably order, the
speed of internal search is increased, which yields the associated routine
number assigned to the keyword.
The rest is simple programming; get the keyword; find the ID number; call
the required routine by ID number.

Oldster

Richard Maine

unread,
Oct 7, 2016, 6:08:41 PM10/7/16
to
Terence <tbwr...@cantv.net> wrote:

> The rest is simple programming; get the keyword; find the ID number; call
> the required routine by ID number.

Looks like all you've done in the elided part is convert a string to an
index number and thus translated the problem of calling a procedure
based on a string to one of calling a procedure based on a number. That
doesn't seem fundamentally much different. Yes, it is "simple
programing", but so was the original problem. Indeed, the OP showed a
simple solution using select case - simple, but just a bit long-winded.

One could do something like use the number to index into an array of
procedure pointers (using the usual hack to create something akin to an
array of pointers). But the essential part of that is the idea to use
procedure pointers as Vladmir and Louis mentioned. Given that basic
idea, I'd consider the details of how one then indexed such pointers to
be the SMOP (small/simple matter of programming).

Or did you have some other trick in mind when you say "call the required
routine by ID number?" I can't think of any other obvious way to do that
directly in Fortran other than via procedure pointers. There are
certainly approaches that lean heavily on things outside of Fortran.
Previous posters mentioned some. Another would be to build a jump table
in assembly and call that from Fortran. One could probably do something
using type-bound procedures instead of procedure pointers, though that's
going in the direction of more complicated instead of less so. There are
contexts where the type-bound procedure thing could make sense.

--
Richard Maine
email: last name at domain . net
dimnain: summer-triangle

FortranFan

unread,
Oct 7, 2016, 6:35:18 PM10/7/16
to
On Friday, October 7, 2016 at 5:43:27 PM UTC-4, Terence wrote:

> ..
>
> You must have a list of your keywords either inside or outside your program.
> So, it is best if OUTSIDE, since this allows the use of ANY USER language by
> just changing the file supplied.
> ..
> The rest is simple programming; get the keyword; find the ID number; call
> the required routine by ID number.
> ..

@Terence,

This is the second time I've noticed you suggest an approach involving ID number and files and so forth, previous occasion being this:
https://groups.google.com/forum/#!topic/comp.lang.fortran/oa9UdyIR10c

You are clearly quite happy with your technique that has served you well over the years and which you now recommend to others in the context of "string" handling. However from what I can infer from your description, it just comes across as "less easy" (however vaguely one might define it!) than the options available in the language.

Will it be possible for you to show some actual code with a fully worked out example along with your analysis of the benefits of your technique relative to other options within the language, such as with (a possibly long) SELECT CASE construct mentioned in the original post?

You may also want to consider a formal publication in "Scientific Programming" or ACM Fortran Forum, etc. if you feel your technique has broader relevance in computing.

Gordon Sande

unread,
Oct 7, 2016, 7:12:49 PM10/7/16
to
On 2016-10-07 21:43:16 +0000, Terence said:

> The rest is simple programming; get the keyword; find the ID number;
> call the required routine by ID number.

When I read what was requested it sure looked like the "required routine"
would also change, evan a new routine. That is either a small source change
or depending upon dynamic loading and linking. The latter does not seem
like something a beginner should use as a first try. Fine for experienced
"system programmers".

campbel...@gmail.com

unread,
Oct 7, 2016, 11:16:30 PM10/7/16
to
For simplicity and clarity, the original proposal of SELECT CASE looks like a good place to start. I haven't seen any suggestion as to why this is a bad idea.
If there are about 100 keywords, you may wish to first scan the keyword for validity and possibly give the keyword a group number/identifier and so have separate SELECT CASE constructs for each group. This may make the coding a bit easier to maintain.
There is also no discussion of "argument(s)". Managing this may make the SELECT CASE a bit long, which may be helped by groups of keywords, based on their argument building.
You may also wish to first map the keyword to a different name, so that multiple keywords could use the same routine, although the original SELECT CASE approach can easily manage this.

First, use your idea, get it working, then see where it needs improving. It will work.

FJ

unread,
Oct 8, 2016, 4:21:36 AM10/8/16
to
In any way, if you want to add a new keyword associated to a specific
treatment, you will have to change something in your program.

And modifying a "select case" does not seem to be the biggest part of the
modification... In addition, all the alternatives mentioned by other people
seem far more complicated than that !

Stefano Zaghi

unread,
Oct 8, 2016, 4:42:09 AM10/8/16
to
Dear Pascal,

As others have already noticed, your "select case" proposal seems to be the most easy (at least clear/concise) solution. You have not provided many details, thus my understanding could be drammatically wrong, but I argued:

+ each keyword needs its own procedure;
+ unclear if in the file processed you have the "specific-association" 'key1 => procedure_foo', or simply a list of keywords to be processed;

The two cases originating from the second point are quite different, but your code have to implement all procedures anyway.

Let us considering 2 scenario.

SIMPLE LIST OF KEYWORDS
Your input file is a list of keys, e.g.

---input file
# list of keywords to be processed
key2 args_for_proc
key567 args_for_proc
...
---end input file


In this case your select case approach is effective for me. All other pure Fortran approaches (namely excluding non Fortran tricks) are very similar (conceptually) to the select case method, i.e. hashtable, "jump table", factory pattern, strategy pattern... could be considered different "flavors" of the same logic. Your main cons, i.e. the need to update the select case for each new keyword, is not eliminated by the other methods, it is only flushed to other kind of updates (ad a new node to the hash table, provide a new strategy...).

THE INPUT FILE "DEFINE" EACH SPECIFIC KEY-PROCEDURE ASSOCIATION
Your input file is a list of keys WITH the associated procedure to be used, e.g.

---input file
# list of keywords/procedures to be processed
key2 process_foo args_for_proc
key567 process_bar args_for_proc
...
---end input file

In this more complex case I still think that your select case approach is one of the best for easy/clearness. However, in this case more complex approach like factory pattern could make more simple the maintainance/improvment of the code.


Nevertheless, if you want to restrict your self on Fortran, all solutions look like a different flavor of select case logic. As a matter of fact, to my knowneldge, Fortran has not the "introspection" capability of other languages (e.g. Python), thus obtaining an "introspective expansion" like "call key_proc(proc='process_foo', key='key1', args=...)" where the string "process_foo" is "expanded" to call your actually implemented "process_foo" procedure is not possible (except if you make the process_foo a stand-alone program that can be called by F08 sys call).

I agree with Campbell: your select case seems very effective. Anyhow, give use a more detailed view of your aim.

My best regards.


Pascal

unread,
Oct 8, 2016, 6:35:48 AM10/8/16
to
On 07/10/16 15:46, Pascal wrote:
> Hi,
>
> I am processing a file which have about a hundred keywords. Each keyword
> would be processed by a particular subroutine.
>
> [...]

Thank you for all the comments, looks like a select case is the
easiest/simplest approach.
Each keyword is associated to a unique subroutine.

I thought that as you can pass a subroutine as argument, there would be
way to dynamically `convert` a string to a subroutine.

Pascal

JerryD

unread,
Oct 8, 2016, 11:38:48 AM10/8/16
to
One other option not mentioned is using a preprocessor on your source code with
an included definition file that contains the keywords and the corresponding
procedure names and arguments. Macro expansion then builds the code for you.

For myself I would probably try a derived type/class that contains the keyword
and procedure pointer and build an array of these initialized in an included file.

Jerry


herrman...@gmail.com

unread,
Oct 8, 2016, 12:52:13 PM10/8/16
to
On Saturday, October 8, 2016 at 3:35:48 AM UTC-7, Pascal wrote:

(snip)

> Thank you for all the comments, looks like a select case is the
> easiest/simplest approach.
> Each keyword is associated to a unique subroutine.

> I thought that as you can pass a subroutine as argument, there would be
> way to dynamically `convert` a string to a subroutine.

Some interpreted languages allow calling subroutines using
a name in a string variable.

For compiled languages, when you pass a subroutine name as
an argument, it is usually converted to the address of the subroutine
at compile time. In some cases, the actual name is available for
printing out in messages, but not for use in calls.

There are sometimes tricks you can play with dynamic
linking to do something similar, but that is usually outside
the language definition.

-- glen

Louis Krupp

unread,
Oct 8, 2016, 1:33:31 PM10/8/16
to
On Sat, 8 Oct 2016 11:35:46 +0100, Pascal <pasc...@parois.net>
wrote:
There is a way; see:

http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html

and

http://stackoverflow.com/questions/38710099/fortran-dynamic-libraries-load-at-runtime

When you add a new keyword, you could write a new subroutine, compile
it, and add it to the shared object or dynamic link library or
whatever it is on your system. When you read a keyword from your
input file, you could use it to generate the name of a symbol in your
shared object (if you're on Linux, etc) and then you could call
dlsym() to get the address of the subroutine. If dlsym() returns NULL
for a keyword, then the keyword's subroutine isn't in the shared
object and you can tell the user that the keyword hasn't been
implemented.

The question is whether or not this sounds like fun. If it does, then
go for it.

Louis

David Jones

unread,
Oct 9, 2016, 1:55:20 PM10/9/16
to
A more direct approach is to replace the idea of using a "subroutine" with
that of using an individual "program" corresponding to each keyword. That
is, use a system level call to run a program whose name is either exactly
the keyword, or derived from it in a standard way, and then pass
information back in a some fixed way using a file. No need to have a
predefined list of possible keywords or to rewrite the main program for
new ones.

For usability, one might either check for the existence of the program
executable or obtain a list of all the executables in the intended program
directory.

The usefulness of this idea clearly depends on your overall context, and
on how much overhead there is in making a system call of this type.

--
Using Opera's mail client: http://www.opera.com/mail/

herrman...@gmail.com

unread,
Oct 9, 2016, 3:45:11 PM10/9/16
to
On Sunday, October 9, 2016 at 10:55:20 AM UTC-7, David Jones wrote:
> On Sat, 08 Oct 2016 11:35:46 +0100, Pascal <pascal..p@parois.net> wrote:

(snip)

> >> I am processing a file which have about a hundred keywords. Each keyword
> >> would be processed by a particular subroutine.

(snip)

> A more direct approach is to replace the idea of using a "subroutine" with
> that of using an individual "program" corresponding to each keyword. That
> is, use a system level call to run a program whose name is either exactly
> the keyword, or derived from it in a standard way, and then pass
> information back in a some fixed way using a file. No need to have a
> predefined list of possible keywords or to rewrite the main program for
> new ones.

It depends much on details not given.

Another way, especially if the different subroutines aren't so different,
is to write one subroutine leaving important parameters as input data,
supplied by an input file. Often enough, this results in a specialized
language for writing the different routines (optimized for the problem
at hand), a compiler for that language generating some form of
intermediate code, and then the program interprets that code,
selecting the routine, read from a file, based on the input string.

I did one once where the different "routines" were actually
pattern matching problems, and it turned out that they could
be implemented as regular expressions. An input file gave
the appropriate regular expression for each case, and
instructions told users how to add new ones later, if needed.

Terence

unread,
Oct 13, 2016, 12:33:34 AM10/13/16
to
"FortranFan" wrote (about Terence's preferred method)
>Will it be possible for you to show some actual code with a fully worked
>out example along >with your analysis of the benefits of your technique
>relative to other options within the >language, such as with (a possibly
>long) SELECT CASE construct mentioned in the original >post?

I thought it was obvious: the 'simple' programming to locate the routine
that follows acquiring the keyword index number beyond a small range, has as
the fastest way, a binary splitting of the range of the index number into
tests in powers of 2, for sub-range section before actually performing any
CASE determination, which calls the actual subroutine.

I used this in all my software where I needed to offer pretty much any
external single-character based language (latino, Greek or Romaji come to
mind); but the same is applicable to modern multiple-byte symbol
identifications.

In the 'good old days', most Fortran compilers constructed a list of actual
routine addresses,
with a null for unsupported indices, so the routine associated with the
index number was an in-line list of actual routine addresses in index order.
Perhaps before your time?

Mind you, I still prefer a computed GOTO over CASE anyway, since this is
usually compiled as a faster selection.

campbel...@gmail.com

unread,
Oct 13, 2016, 1:07:41 AM10/13/16
to
On Thursday, October 13, 2016 at 3:33:34 PM UTC+11, Terence wrote:
>
> Mind you, I still prefer a computed GOTO over CASE anyway, since this is
> usually compiled as a faster selection.

How true is this claim ? and is the speed requirement of this and other search techniques really necessary ?

The original premise was that a subroutine is available for each keyword, so is a speedy selection of the subroutine the problem ?
Dynamic definition of keywords ? when a specific subroutine is required to process the identified keyword.

I think some of the ideas expressed in this thread are a long way from assisting the original post.

Stefano Zaghi

unread,
Oct 13, 2016, 3:38:12 AM10/13/16
to
Dear Terence,

Il giorno giovedì 13 ottobre 2016 06:33:34 UTC+2, Terence ha scritto:
> I thought it was obvious: the 'simple' programming to locate the routine
> that follows acquiring the keyword index number beyond a small range, has as
> the fastest way, a binary splitting of the range of the index number into
> tests in powers of 2, for sub-range section before actually performing any
> CASE determination, which calls the actual subroutine.

Indeed, I do not understand you. A concrete example, even in pseudo code, applied to the scenario of OP is really welcome to better understand your technique. In particular, I cannot understand in "what" and how it is different from the very concise and clear select case approach.

I agree with campbel that for the OP needs the select case approach looks well suited.

> Mind you, I still prefer a computed GOTO over CASE anyway, since this is
> usually compiled as a faster selection.

Well, I disagree ever on such "sharp" sentences...

Can you provide a concrete benchmark proving that goto is faster than select case (in the OP scenario)?

Moreover, even in the case some benchmarks show that, how big is the speedup?

In my opinion, what really matter when talking about "goto" is all another kind of issues with respect the speed: gotos produce unreadable, non maintainable, spaghetti-code that strongly prevent and limit important features like conciseness and clearness and strongly impact also on speed that is so important for you (preventing optimization, vectorization, multi-threading...).

Nope, nowadays the suggestion to use goto is anachronistic and I think that goto should be considered "bad practice".

My best regards.


FJ

unread,
Oct 13, 2016, 12:28:02 PM10/13/16
to
Le 13/10/2016 à 09:37, Stefano Zaghi a écrit :
> Dear Terence,
>
> Il giorno giovedì 13 ottobre 2016 06:33:34 UTC+2, Terence ha scritto:
>> I thought it was obvious: the 'simple' programming to locate the routine
>> that follows acquiring the keyword index number beyond a small range, has
>> as
>> the fastest way, a binary splitting of the range of the index number into
>> tests in powers of 2, for sub-range section before actually performing any
>>
>> CASE determination, which calls the actual subroutine.
>
> Indeed, I do not understand you. A concrete example, even in pseudo code,
> applied to the scenario of OP is really welcome to better understand your
> technique. In particular, I cannot understand in "what" and how it is
> different from the very concise and clear select case approach.
>
> I agree with campbel that for the OP needs the select case approach looks
> well suited.
>
>> Mind you, I still prefer a computed GOTO over CASE anyway, since this is
>> usually compiled as a faster selection.
>
> Well, I disagree ever on such "sharp" sentences...
>
> Can you provide a concrete benchmark proving that goto is faster than select
> case (in the OP scenario)?

I did such benchmark few years ago ... and Terence is right !

>
> Moreover, even in the case some benchmarks show that, how big is the
> speedup?

Most often, the speedup does not matter. And a "select case" construct is
easier to extend.

>
> In my opinion, what really matter when talking about "goto" is all another
> kind of issues with respect the speed: gotos produce unreadable, non
> maintainable, spaghetti-code that strongly prevent and limit important
> features like conciseness and clearness and strongly impact also on speed that
> is so important for you (preventing optimization, vectorization,
> multi-threading...).

For normal GOTO, your are right but computed goto is a quit clear construct
which looks like a select case despite the high number of labels.

Richard Maine

unread,
Oct 13, 2016, 2:42:53 PM10/13/16
to
FJ <francois.jacq@invalid> wrote:

> Most often, the speedup does not matter. And a "select case" construct is
> easier to extend.

Indeed the OP mentioned nothing about speed, and considering that it is
used to select a procedure to call, it seems unlikely that the speed of
the selection would be significant compared to the overhead of the
subroutine calls unless they were the most trivial of inlineable
subroutines, which doesn't seem likely from the problem description.
Seems to me that speed is likely to be very low on the list of concerns
here, far behind things like clarity, extensibility, etc., which were
the things the OP asked about.

> For normal GOTO, your are right but computed goto is a quit clear construct
> which looks like a select case despite the high number of labels.

Don't forget about cmputed goto being formally obsolescent in the
standard. That might not matter to some people. To others, it can be a
deal-breaker due to policy dictates.

FortranFan

unread,
Oct 13, 2016, 3:46:33 PM10/13/16
to
On Thursday, October 13, 2016 at 12:28:02 PM UTC-4, FJ wrote:

> Le 13/10/2016 à 09:37, Stefano Zaghi a écrit :
> ..
> >
> > Can you provide a concrete benchmark proving that goto is faster than select
> > case (in the OP scenario)?
>
> I did such benchmark few years ago ... and Terence is right !
>
> ..

@FJ,

It'll be nice if you can dig it up or provide some reference for your study because note Terence's point was, "I still prefer a computed GOTO over CASE anyway, since this is usually compiled as a faster selection".

I ask because I have a tough time understanding why there will much of any difference in the compilers today between the two constructs, especially considering comments I recall seeing on the big commercial compiler forum that suggested once compiler optimization is brought to bear, it would make little to no performance difference. The recommendation was to write code that expressed the algorithm and programmer intent and things like that best.

OP says there are about "a hundred keywords" with CASE construct for each and which can grow further over time; imagine the computed GOTO for such a scenario and the chance of coding errors with the labels!?

FortranFan

unread,
Oct 13, 2016, 4:56:01 PM10/13/16
to
On Thursday, October 13, 2016 at 12:33:34 AM UTC-4, Terence wrote:

> ..
>
> I thought it was obvious: the 'simple' programming to locate the routine
> that follows acquiring the keyword index number beyond a small range, has as
> the fastest way, a binary splitting of the range of the index number into
> tests in powers of 2, for sub-range section before actually performing any
> CASE determination, which calls the actual subroutine.
>

@Terence,

Well, please note your explanation is, unfortunately, neither "simple" nor "obvious" to me in the least bit and it has a lot to do with my inadequate background, especially with programming toward highly resource-constrained target computing platforms and environments. But looking at a couple of other comments by Stefano Zaghi and John Campbell, in the particular case of this thread though, it may be not relevant. That is, they have the same concerns and doubts, especially with respect to OP's question, "I am wondering if there is an easier way". So our request to you is earnest: can you show with actual code how your approach helps in this regard?

> ..
>
> In the 'good old days', most Fortran compilers constructed .. an in-line list of actual routine addresses in index order. Perhaps before your time?
>

Yes, indeed. This is also another reason for my request to you to show some actual code. You definitely have succeeded extensively with your approach; others can learn from your vast algorithmic and other coding inventions and experience. If you can document all that in some fashion, perhaps in the form of online blogs or papers or even a book, it will be indeed valuable for the following generations.

> Mind you, I still prefer a computed GOTO over CASE anyway, since this is
> usually compiled as a faster selection.

As I commented in response to the post by FJ, what you state here is contrary to the current 'conventional wisdom' that once optimization kicks in, there should be little to no performance difference between the two constructs. So a developer can then stop worrying about such 'premature optimization' - the kind decried by Knuth - and focus on writing code that 'best' expresses the algorithm, the coding purpose, and so forth. Note the Fortran standard states, "The computed GO TO has been superseded by the SELECT CASE construct, which is a generalized, easier to use, and clearer means of expressing the same computation."

Please keep in mind I'm not asking you to report anything fancy, just code snippets around the need expressed in the original post. If that's too vague, you can even take the simple code below (which should express OP's current approach adequately), modify it as you see fit and share your changes here.

-- begin code --
module procs_m

implicit none

private

public :: s1
public :: s2

contains

subroutine s1( msg )

character(len=*), intent(in) :: msg

print *, "s1 gets the message: ", msg

return

end subroutine s1

subroutine s2( msg )

character(len=*), intent(in) :: msg

print *, "s2 gets the message: ", msg

return

end subroutine s2

end module procs_m

module m

use procs_m, only : s1, s2

implicit none

private

character(len=*), parameter, public :: keywords(*) = [ character(len=2) :: "s1", "s2" ]

public :: s

contains

subroutine s( keyword, msg )

character(len=*), intent(in) :: keyword
character(len=*), intent(in) :: msg

select case ( keyword )

case ( keywords(1) )

call s1( msg )

case ( keywords(2) )

call s2( msg)

case default

print *, "s: invalid keyword of ", keyword
return

end select

return

end subroutine s

end module m

program p

use m, only : s, keywords

implicit none

character(len=:), allocatable :: keyword
character(len=*), parameter :: Message = "Keep it simple!"

keyword = keywords(2)
call s( keyword, Message )

keyword = keywords(1)
call s( keyword, Message )

stop

end program p
-- end code --

Upon execution, the output is (obviously):
s2 gets the message: Keep it simple!
s1 gets the message: Keep it simple!



dpb

unread,
Oct 13, 2016, 6:56:31 PM10/13/16
to
On 10/13/2016 2:46 PM, FortranFan wrote:
> On Thursday, October 13, 2016 at 12:28:02 PM UTC-4, FJ wrote:
>> Le 13/10/2016 à 09:37, Stefano Zaghi a écrit :
>> ..
>>>
>>> Can you provide a concrete benchmark proving that goto is faster than select
>>> case (in the OP scenario)?
>>
>> I did such benchmark few years ago ... and Terence is right !
>>
>> ..
>
> @FJ,
...

> I ask because I have a tough time understanding why there will much
> of any difference in the compilers today between the two constructs,
> especially considering comments I recall seeing on the big commercial
> compiler forum that suggested once compiler optimization is brought to
> bear, it would make little to no performance difference. The
> recommendation was to write code that expressed the algorithm and
> programmer intent and things like that best.
>
> OP says there are about "a hundred keywords" with CASE construct for
> each and which can grow further over time; imagine the computed GOTO
> for such a scenario and the chance of coding errors with the
> labels!?

I'm not compiler writer of any sort and certainly not when it gets to
optimizing the results of a basic translation but I wonder it any
comparison that showed a difference would be related to whether the
lookup selection for the CASE turned out to be a serial series of
comparisons as opposed to a jump table to a precomputed location in the
GOTO? I'm quite possibly all wet here and there's nothing whatever like
that happening, too... :)

herrman...@gmail.com

unread,
Oct 14, 2016, 1:01:31 AM10/14/16
to
On Thursday, October 13, 2016 at 3:56:31 PM UTC-7, dpb wrote:
> On 10/13/2016 2:46 PM, FortranFan wrote:

(snip)

> > I ask because I have a tough time understanding why there will much
> > of any difference in the compilers today between the two constructs,
> > especially considering comments I recall seeing on the big commercial
> > compiler forum that suggested once compiler optimization is brought to
> > bear, it would make little to no performance difference. The
> > recommendation was to write code that expressed the algorithm and
> > programmer intent and things like that best.

(snip)

> I'm not compiler writer of any sort and certainly not when it gets to
> optimizing the results of a basic translation but I wonder it any
> comparison that showed a difference would be related to whether the
> lookup selection for the CASE turned out to be a serial series of
> comparisons as opposed to a jump table to a precomputed location in the
> GOTO? I'm quite possibly all wet here and there's nothing whatever like
> that happening, too... :)

I am not at all sure what compilers now generate for select/case.

One hopes that in the case of sequential CASE values that a jump table
is used instead of a sequence of conditional tests, but you never know
until you try and look at the generated code.

Compilers are getting better all the time, but I don't know
about this one.

Stefano Zaghi

unread,
Oct 14, 2016, 3:39:09 AM10/14/16
to
Dear FJ,

Il giorno giovedì 13 ottobre 2016 18:28:02 UTC+2, FJ ha scritto:
> I did such benchmark few years ago ... and Terence is right !

I do not want that you think there is something personal, but until you provide a concrete benchmark with the possibility to see your code, your sentence like the one of Terence has not any value: provide a benchmark a let us to repeat your test with the compilers available and then we can discuss about the possible speedup.

> Most often, the speedup does not matter. And a "select case" construct is
> easier to extend.
> For normal GOTO, your are right but computed goto is a quit clear construct
> which looks like a select case despite the high number of labels.

Well, a long list (order of O(100) for the OP case) labels is really unreadable. Moreover, what is really worse is the fact that the labels could be placed everywhere, it is up to the programmer being "clean" and put the labels in a clear sequence, but you cannot rely on that. Goto (computed or not) let the algorithm jump everywhere, thus it result into unmaintainable and unreadable code that prevent even further optimization like vectorization and multi-threading. There are good reasons why computed goto are tagged as "obsolescent".

Anyhow, as Richard noted, the OP request for a more easy/clean approach to maintain/improve a long list of procedures called accordingly to some keywords-jumping mechanism, (s)he does not ask how to speedup the calling. As a consequence, I do not understand the Terence suggestion: aside that I still completely do not understand the "simple programming" part of his approach (an example would be very helpful for me to learn a new thing), the part related to the goto is really counterproductive with respect the OP's request: goto is not cleaner with respect select case, it is not more easy extensible than select case, it is not more easy "optimizable" than select case, the only (assumed and not proven) pros is "a possible" faster jump to the correct procedure call and how faster is not even claimed. As I already said, promoting goto nowadays is anachronistic and I hope to have explained my reasons.

My best regards.

dpb

unread,
Oct 14, 2016, 9:54:20 AM10/14/16
to
On 10/14/2016 12:01 AM, herrman...@gmail.com wrote:
...

> I am not at all sure what compilers now generate for select/case.
>
> One hopes that in the case of sequential CASE values that a jump table
> is used instead of a sequence of conditional tests, but you never know
> until you try and look at the generated code.
>
> Compilers are getting better all the time, but I don't know
> about this one.

Well, I'd surely think by now with optimization would do so as well
(generate the jump table, that is); my conjecture was based solely by
inference to the (more-or-less dated?) previous comparison that was
then, at least, slower for some particular test case(s).

I was hypothesizing (the more-or-less obvious I think?) reason for that
to be so then, but possibly or likely not necessarily the case for more
recent compilers presuming things that prevent optimizations aren't
present in the code, anyway.

Gary Scott

unread,
Oct 15, 2016, 12:05:13 PM10/15/16
to
I just did a small test. I TRIED to model a select case with 5 case
selections and I TRIED to design a goto construct that did the same
thing. Probably not exactly. The computed goto was clearly faster in
this test. On average, the select case took 40ns, the computed goto
took 31ns. How would you like to improve this? IVF option /O3
(with /Od, results are 48ns and 36ns)

knt = 1
do i = 1,size(ttag)-1,2
call svTTReadTicks(tTag(i))

select case(knt)
case(1)
knt = 2
case(2)
knt = 3
case(3)
knt = 1
case(4)
knt = 5
case(5)
knt = 4
end select

call svTTReadTicks(tTag(i+1))
end do

do i = 1,size(ttag),2
call svTTTicks2Value(ttag(i),ttValue1)
call svTTTicks2Value(ttag(i+1),ttValue2)
write(10,'(f19.12)')ttValue2-ttValue1
end do


knt = 1
do i = 1,size(ttag)-1,2
call svTTReadTicks(tTag(i))

goto (1,2,3,4,5), knt

1 knt = 2
go to 10
2 knt = 3
go to 10
3 knt = 1
go to 10
4 knt = 5
go to 10
5 knt = 4

10 call svTTReadTicks(tTag(i+1))
end do
write(10,*)' '
write(10,*)'goto'
do i = 1,size(ttag),2
call svTTTicks2Value(ttag(i),ttValue1)
call svTTTicks2Value(ttag(i+1),ttValue2)
write(10,'(f19.12)')ttValue2-ttValue1
end do

Gary Scott

unread,
Oct 15, 2016, 1:16:02 PM10/15/16
to
Interestingly, this IF construct was nearly identical on average as the
select case above. These 3 tests are performed serially in the same
run. I performed 10 times (10k loop samples each) with same relative
results +/- 3ns. In one run, the if construct was 4ns faster than
select case, certainly a fluke of machine state.


write(10,*)'IF'
knt = 1
do i = 1,size(ttag)-1,2
call svTTReadTicks(tTag(i))

if (knt == 1) then
knt = 2
else if (knt == 2) then
knt = 3
else if (knt == 3) then
knt = 1
else if (knt == 4) then
knt = 5
else if (knt == 5) then
knt = 4
end if

herrman...@gmail.com

unread,
Oct 15, 2016, 1:59:17 PM10/15/16
to
On Saturday, October 15, 2016 at 9:05:13 AM UTC-7, Gary Scott wrote:
> On 10/14/2016 8:54 AM, dpb wrote:
> > On 10/14/2016 12:01 AM, herrmanns...@gmail.com wrote:

> >> I am not at all sure what compilers now generate for select/case.

> >> One hopes that in the case of sequential CASE values that a jump table
> >> is used instead of a sequence of conditional tests, but you never know
> >> until you try and look at the generated code.

(snip)

> I just did a small test. I TRIED to model a select case with 5 case
> selections and I TRIED to design a goto construct that did the same
> thing. Probably not exactly. The computed goto was clearly faster in
> this test. On average, the select case took 40ns, the computed goto
> took 31ns. How would you like to improve this? IVF option /O3
> (with /Od, results are 48ns and 36ns)

Just to be sure, could you try one exchanging the select/case and goto
parts, such that the goto was first, and select/case second?

That is, to be sure that it isn't any start up or cache effects?

You could also put both inside a single DO loop, instead of two loops.

There are so many tricks for compilers and processors, it is hard to
know what one might do.

You could also post the generated assembly code for comparison.

thanks,

-- glen

Gary Scott

unread,
Oct 15, 2016, 3:11:13 PM10/15/16
to
Changing the order does seem to equalize the performance except that the
first series regardless of type seems to have more outlier samples
(cache misses)? Reducing the number of samples eliminates the
measurable difference (with this method). I need to modify the sequence
as it is only executing the first few statements though.

I guess it's hard to say there's a difference with this test method.

Gary Scott

unread,
Oct 15, 2016, 3:32:37 PM10/15/16
to
modified to select 1 > 5 > 4 > 3 > 2 > 1...no difference. optimization
on or off, first test always takes slightly longer than the second and
third whether it is an SC an IF or a goto test but appears primarily due
to outlier samples. Most samples are indistinguishable.

Gary Scott

unread,
Oct 15, 2016, 3:58:13 PM10/15/16
to
Ah, "solution", I added a "dummy" test repeating the SC at the top.
After doing this, the average timing for each subsequent type, select
case, computed goto, and if statement are now identical (both /Od
(+/-3ns) and /O3 (+/-1ns), 1000 samples)...hmmm, I had actually planned
to do some real work today...

Suspicious...

write(10,*)' '
write(10,*)'DummySC'
knt = 1
do i = 1,size(ttag)-1,2
call svTTReadTicks(tTag(i))

select case(knt)
case(1)
knt = 5
case(2)
knt = 4
case(3)
knt = 3
case(4)
knt = 2
case(5)
knt = 1
end select

call svTTReadTicks(tTag(i+1))
end do

do i = 1,size(ttag)-1,2
call svTTTicks2Value(ttag(i),ttValue1)
call svTTTicks2Value(ttag(i+1),ttValue2)
write(10,'(f19.12)')ttValue2-ttValue1
end do

write(10,*)' '
write(10,*)'SC'
knt = 1
do i = 1,size(ttag)-1,2
call svTTReadTicks(tTag(i))

select case(knt)
case(1)
knt = 5
case(2)
knt = 4
case(3)
knt = 3
case(4)
knt = 2
case(5)
knt = 1
end select

call svTTReadTicks(tTag(i+1))
end do

do i = 1,size(ttag)-1,2
call svTTTicks2Value(ttag(i),ttValue1)
call svTTTicks2Value(ttag(i+1),ttValue2)
write(10,'(f19.12)')ttValue2-ttValue1
end do

write(10,*)' '
write(10,*)'goto'
knt = 1
do i = 1,size(ttag)-1,2
call svTTReadTicks(tTag(i))

goto (1,2,3,4,5), knt

1 knt = 5
go to 10
2 knt = 4
go to 10
3 knt = 3
go to 10
4 knt = 2
go to 10
5 knt = 1

10 call svTTReadTicks(tTag(i+1))
end do


do i = 1,size(ttag)-1,2
call svTTTicks2Value(ttag(i),ttValue1)
call svTTTicks2Value(ttag(i+1),ttValue2)
write(10,'(f19.12)')ttValue2-ttValue1
end do

write(10,*)' '
write(10,*)'IF'
knt = 1
do i = 1,size(ttag)-1,2
call svTTReadTicks(tTag(i))

if (knt == 1) then
knt = 5
else if (knt == 2) then
knt = 4
else if (knt == 3) then
knt = 3
else if (knt == 4) then
knt = 2
else if (knt == 5) then
knt = 1
end if

call svTTReadTicks(tTag(i+1))
end do

do i = 1,size(ttag)-1,2

Stefano Zaghi

unread,
Oct 15, 2016, 4:03:58 PM10/15/16
to
Dear Gary,

thank you for your test. However, I think that your test has some weakness:

1. you did not provide a full program, thus we cannot reproduce it;
2. there is not details about the architecture you have used;
3. your test seems far from the OP scenario: the work done inside each branch should not be null, on the contrary it seems that is huge compared to the time of the branching itself;
4. your test seems to measure the whole cpu-time of the whole program rather the time of only the branching algorithm (with the inside worker time).

I have done for you another test. Consider that I have "resurrected" my old netbook for you :-)

The results of my tests are reported here https://gist.github.com/szaghi/3b761e66234a90d4815ad30a4d81354c within the complete program, the details of the compiler used and of the PC.

My test indicates that all the three branching flow are comparable and goto is the worse.

I have tried to address what I think your test missed:

1. I provide a complete program;
2. I tried to mimic a varying work-load into each branch;
3. I tried to enter into each branch randomically (pseudo-random at least);
4. I tried to measure only the branching time;

I do not consider much "significative" test, but even your is somehow meaningless. Goto is to be avoided for much important reasons than the (supposed) higher speed of execution.

My best regards.

Gary Scott

unread,
Oct 15, 2016, 4:29:34 PM10/15/16
to
I was only interested in testing the "branch selection" process. I
understand that optimizers may optimize things away. I sampled without
optimization to assess the differences and did not note any substantial
difference.

This is an HP p6210, 8GB, 2.6Ghz, AMD620, WIN10 so IVF may or may not
generate the best code.

No, there are problem/solution domains where performance is imperative.
If GOTO offered a performance advantage, it would be entirely
appropriate to us it. I have not used it in decades, but if I had such
a need, I would not hesitate, if I had verified there was such a benefit
and such a benefit was important to the problem solution.


Gary Scott

unread,
Oct 15, 2016, 4:36:36 PM10/15/16
to
Correction, I do use GOTo for a very small number of cases where error
exit processing otherwise would be cumbersome. It would be possible in
some cases to have a giant bounding do loop, but these become messier to
follow when you are processing 100s of GUI callbacks. It can be easier
and more clear to separate the callback processing from the error exit
processing this way.

FortranFan

unread,
Oct 15, 2016, 6:47:42 PM10/15/16
to
On Saturday, October 15, 2016 at 3:58:13 PM UTC-4, Gary Scott wrote:

> ..
>
> Suspicious...
>
> ..


You need to provide complete details for any meaningful discussion starting with a reproducible case, otherwise I'll suspicious indeed, for it provides me with no takeaways.

FortranFan

unread,
Oct 15, 2016, 7:12:00 PM10/15/16
to
On Saturday, October 15, 2016 at 4:03:58 PM UTC-4, Stefano Zaghi wrote:

> ..
>
> My test indicates that all the three branching flow are comparable and goto is the worse.
>
> I have tried to address what I think your test missed:
>
> 1. I provide a complete program;
> 2. I tried to mimic a varying work-load into each branch;
> 3. I tried to enter into each branch randomically (pseudo-random at least);
> 4. I tried to measure only the branching time;
>
> .. Goto is to be avoided for much important reasons than the (supposed) higher speed of execution.
>
> ..


Stefano,

Great work, you should create a Fortran MYTHBUSTERS collection on GitHub!!
https://en.wikipedia.org/wiki/MythBusters

Fyi, I was thinking somewhat along the same lines and ran a test around the SAME time as your post above - I list the details below which you can review and discard/include in any way you see fit. My read is also the same, there is hardly any discernible difference in CPU performance between the two approaches, but coders may again want to be reminded,

a) SELECT CASE helps in writing clear code that should be easier to understand and maintain,

b) computed GOTO is obsolescent in the Fortran standard, and

c) SELECT CASE works with integer, logical, AND *CHARACTER* scalar expressions whereas computed GOTO only uses scalar numeric expressions that may be converted to integer type.

Readers need to keep point (c) in mind, especially with respect to the original post that showed constructs such as << CASE ('keyword1') >>. A coder would then need to take some extra action - use of some integer tables, perhaps - to utilize computed GOTO statements.

-- begin case --
module mykinds_m

use, intrinsic :: iso_fortran_env, only : I4 => int32, WP => real64

implicit none

real(WP), parameter :: ZERO = 0.0_wp

end module mykinds_m

module procs_m

use mykinds_m, only : WP, ZERO

implicit none

contains

subroutine s1( n, r )

!.. Argument list
integer, intent(in) :: n
real(WP), intent(inout) :: r

!.. Local variables
integer :: v_size
integer :: istat
real(WP), allocatable :: v(:)

v_size = 2**( min(n,10) )
allocate( v(v_size), stat=istat )
if ( istat /= 0 ) then
print *, "s1: allocation of v failed: v_size, stat = ", v_size, istat
stop
end if

call random_number( v )

r = norm2( v )

return

end subroutine s1

subroutine s2( n, r )

!.. Argument list
integer, intent(in) :: n
real(WP), intent(inout) :: r

!.. Local variables
integer :: v_size
integer :: istat
real(WP), allocatable :: v(:)

v_size = 2**( min(n,10) )
allocate( v(v_size), stat=istat )
if ( istat /= 0 ) then
print *, "s2: allocation of v failed: v_size, stat = ", v_size, istat
stop
end if

call random_number( v )

r = norm2( v )

return

end subroutine s2

subroutine s3( n, r )

!.. Argument list
integer, intent(in) :: n
real(WP), intent(inout) :: r

!.. Local variables
integer :: v_size
integer :: istat
real(WP), allocatable :: v(:)

v_size = 2**( min(n,10) )
allocate( v(v_size), stat=istat )
if ( istat /= 0 ) then
print *, "s3: allocation of v failed: v_size, stat = ", v_size, istat
stop
end if

call random_number( v )

r = norm2( v )

return

end subroutine s3

subroutine s4( n, r )

!.. Argument list
integer, intent(in) :: n
real(WP), intent(inout) :: r

!.. Local variables
integer :: v_size
integer :: istat
real(WP), allocatable :: v(:)

v_size = 2**( min(n,10) )
allocate( v(v_size), stat=istat )
if ( istat /= 0 ) then
print *, "s4: allocation of v failed: v_size, stat = ", v_size, istat
stop
end if

call random_number( v )

r = norm2( v )

return

end subroutine s4

subroutine s5( n, r )

!.. Argument list
integer, intent(in) :: n
real(WP), intent(inout) :: r

!.. Local variables
integer :: v_size
integer :: istat
real(WP), allocatable :: v(:)

v_size = 2**( min(n,10) )
allocate( v(v_size), stat=istat )
if ( istat /= 0 ) then
print *, "s5: allocation of v failed: v_size, stat = ", v_size, istat
stop
end if

call random_number( v )

r = norm2( v )

return

end subroutine s5

subroutine s6( n, r )

!.. Argument list
integer, intent(in) :: n
real(WP), intent(inout) :: r

!.. Local variables
integer :: v_size
integer :: istat
real(WP), allocatable :: v(:)

v_size = 2**( min(n,10) )
allocate( v(v_size), stat=istat )
if ( istat /= 0 ) then
print *, "s6: allocation of v failed: v_size, stat = ", v_size, istat
stop
end if

call random_number( v )

r = norm2( v )

return

end subroutine s6

subroutine s7( n, r )

!.. Argument list
integer, intent(in) :: n
real(WP), intent(inout) :: r

!.. Local variables
integer :: v_size
integer :: istat
real(WP), allocatable :: v(:)

v_size = 2**( min(n,10) )
allocate( v(v_size), stat=istat )
if ( istat /= 0 ) then
print *, "s7: allocation of v failed: v_size, stat = ", v_size, istat
stop
end if

call random_number( v )

r = norm2( v )

return

end subroutine s7

subroutine s8( n, r )

!.. Argument list
integer, intent(in) :: n
real(WP), intent(inout) :: r

!.. Local variables
integer :: v_size
integer :: istat
real(WP), allocatable :: v(:)

v_size = 2**( min(n,10) )
allocate( v(v_size), stat=istat )
if ( istat /= 0 ) then
print *, "s8: allocation of v failed: v_size, stat = ", v_size, istat
stop
end if

call random_number( v )

r = norm2( v )

return

end subroutine s8

subroutine s9( n, r )

!.. Argument list
integer, intent(in) :: n
real(WP), intent(inout) :: r

!.. Local variables
integer :: v_size
integer :: istat
real(WP), allocatable :: v(:)

v_size = 2**( min(n,10) )
allocate( v(v_size), stat=istat )
if ( istat /= 0 ) then
print *, "s9: allocation of v failed: v_size, stat = ", v_size, istat
stop
end if

call random_number( v )

r = norm2( v )

return

end subroutine s9

subroutine s10( n, r )

!.. Argument list
integer, intent(in) :: n
real(WP), intent(inout) :: r

!.. Local variables
integer :: v_size
integer :: istat
real(WP), allocatable :: v(:)

v_size = 2**( min(n,10) )
allocate( v(v_size), stat=istat )
if ( istat /= 0 ) then
print *, "s10: allocation of v failed: v_size, stat = ", v_size, istat
stop
end if

call random_number( v )

r = norm2( v )

return

end subroutine s10

end module procs_m

module m

use procs_m

implicit none

private

character(len=*), parameter, public :: keywords(*) = [ character(len=3) :: "s1", "s2", "s3", &
"s4", "s5", "s6", "s7", "s8", "s9", "s10" ]
integer, parameter, public :: ikeys(*) = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]

public :: s_slc
public :: s_cgt

contains

subroutine s_slc( keyword, n, r )

character(len=*), intent(in) :: keyword
integer, intent(in) :: n
real(WP), intent(inout) :: r

select case ( keyword )

case ( keywords(1) )

call s1( n, r )

case ( keywords(2) )

call s2( n, r)

case ( keywords(3) )

call s3( n, r)

case ( keywords(4) )

call s4( n, r)

case ( keywords(5) )

call s5( n, r)

case ( keywords(6) )

call s6( n, r)

case ( keywords(7) )

call s7( n, r)

case ( keywords(8) )

call s8( n, r)

case ( keywords(9) )

call s9( n, r)

case ( keywords(10) )

call s10( n, r)

case default

print *, "s: invarid keyword of ", keyword
return

end select

return

end subroutine s_slc

subroutine s_cgt( ikey, n, r )

integer, intent(in) :: ikey
integer, intent(in) :: n
real(WP), intent(inout) :: r

goto (1,2,3,4,5,6,7,8,9,10), ikey

1 continue
call s1( n, r )
go to 99

2 continue
call s2( n, r )
go to 99

3 continue
call s3( n, r )
go to 99

4 continue
call s4( n, r )
go to 99

5 continue
call s5( n, r )
go to 99

6 continue
call s6( n, r )
go to 99

7 continue
call s8( n, r )
go to 99

8 continue
call s8( n, r )
go to 99

9 continue
call s9( n, r )
go to 99

10 continue
call s10( n, r )
go to 99 ! wonder if compiler optimization eliminates this

99 continue
return

end subroutine s_cgt

end module m
program p

use mykinds_m, only : I4, WP, ZERO
use m, only : s_slc, s_cgt, keywords

implicit none

!..
integer, parameter :: MAXREPEAT = 10
integer, parameter :: MAXTRIAL = 2**10
integer :: Idx(MAXTRIAL)
integer :: Counter
integer :: j
real(WP) :: Start_Time = ZERO
real(WP) :: End_Time = ZERO
real(WP) :: Ave_Time = ZERO
real(WP) :: CpuTimes_SLC(MAXREPEAT)
real(WP) :: CpuTimes_CGT(MAXREPEAT)
real(WP) :: r(MAXTRIAL)
real(WP) :: x_norm
character(len=*), parameter :: FMT_CPU = "(a, t40, g0, a)"

print *, "Mythbuster #1: SELECT CASE vs COMPUTED GOTO" // new_line("")

CpuTimes_SLC = ZERO
CpuTimes_CGT = ZERO

print *, "SELECT CASE:"
Loop_Repeat_Slc: do Counter = 1, MAXREPEAT

print *, " Trial ", Counter

call random_number(r)
Idx = int( r*10.0_wp, kind=kind(Idx) ) + 1

!..
call my_cpu_time(Start_Time)

do j = 1, MAXTRIAL

call s_slc( keywords( Idx(j) ), Idx(j), x_norm )

end do

call my_cpu_time(End_Time)

CpuTimes_SLC(Counter) = (End_Time - Start_Time)

write(*, fmt=FMT_CPU) " CPU Time: ", CpuTimes_SLC(Counter), " seconds."

end do Loop_Repeat_Slc

print *, "COMPUTED GOTO:"
Loop_Repeat_Cgt: do Counter = 1, MAXREPEAT

print *, " Trial ", Counter

call random_number(r)
Idx = int( r*10.0_wp, kind=kind(Idx) ) + 1

!..
call my_cpu_time(Start_Time)

do j = 1, MAXTRIAL

call s_cgt( Idx(j), Idx(j), x_norm )

end do

call my_cpu_time(End_Time)

CpuTimes_CGT(Counter) = (End_Time - Start_Time)

write(*, fmt=FMT_CPU) " CPU Time: ", CpuTimes_CGT(Counter), " seconds."

end do Loop_Repeat_Cgt


!.. Average CPU time: exclude highest and lowest values
Ave_Time = sum(CpuTimes_SLC)
Ave_Time = Ave_Time - maxval(CpuTimes_SLC) - minval(CpuTimes_SLC)
Ave_Time = Ave_Time/real(MAXREPEAT-2, kind=WP)
write(*, fmt=FMT_CPU) "SELECT CASE: Average CPU Time ", Ave_Time," seconds."

!.. Average CPU time: exclude highest and lowest values
Ave_Time = sum(CpuTimes_CGT)
Ave_Time = Ave_Time - maxval(CpuTimes_CGT) - minval(CpuTimes_CGT)
Ave_Time = Ave_Time/real(MAXREPEAT-2, kind=WP)
write(*, fmt=FMT_CPU) "COMPUTED GOTO: Average CPU Time ", Ave_Time," seconds."

!..
stop

contains

subroutine my_cpu_time( time )

!.. Argument list
real(WP), intent(inout) :: time

!.. Local variables
integer(I4) :: tick
integer(I4) :: rate

call system_clock (tick, rate)

time = real(tick, kind=kind(time) ) / real(rate, kind=kind(time) )

return

end subroutine my_cpu_time

end program p
-- end case --

Upon execution with Intel Fortran with /O2 on a Windows 7 laptop, Intel i5 CPU 2.7 GHz, 8 GB machine,

-- begin results --
Mythbuster #1: SELECT CASE vs COMPUTED GOTO

SELECT CASE:
Trial 1
CPU Time: .9999999892897904E-03 seconds.
Trial 2
CPU Time: .1999999978579581E-02 seconds.
Trial 3
CPU Time: .9999999892897904E-03 seconds.
Trial 4
CPU Time: .1999999978579581E-02 seconds.
Trial 5
CPU Time: .2000000007683411E-02 seconds.
Trial 6
CPU Time: .2000000007683411E-02 seconds.
Trial 7
CPU Time: .1000000018393621E-02 seconds.
Trial 8
CPU Time: .9999999892897904E-03 seconds.
Trial 9
CPU Time: .1999999978579581E-02 seconds.
Trial 10
CPU Time: .2000000007683411E-02 seconds.
COMPUTED GOTO:
Trial 1
CPU Time: .1000000018393621E-02 seconds.
Trial 2
CPU Time: .2000000007683411E-02 seconds.
Trial 3
CPU Time: .2000000007683411E-02 seconds.
Trial 4
CPU Time: .1000000018393621E-02 seconds.
Trial 5
CPU Time: .9999999892897904E-03 seconds.
Trial 6
CPU Time: .1000000018393621E-02 seconds.
Trial 7
CPU Time: .2000000007683411E-02 seconds.
Trial 8
CPU Time: .1999999978579581E-02 seconds.
Trial 9
CPU Time: .2000000007683411E-02 seconds.
Trial 10
CPU Time: .2000000007683411E-02 seconds.

SELECT CASE: Average CPU Time .1624999993509846E-02 seconds.
COMPUTED GOTO: Average CPU Time .1625000008061761E-02 seconds.
-- end results --

Basically all that any CPU time measurement indicates is some statistical mean of the keyword-processor subroutine.

dpb

unread,
Oct 15, 2016, 7:59:40 PM10/15/16
to
On 10/15/2016 3:03 PM, Stefano Zaghi wrote:
...

> My test indicates that all the three branching flow are comparable and goto is the worse.
...

It'd be most informative to see what the code generator produced for the
switch logic between the three to account for those results.

Gary Scott

unread,
Oct 15, 2016, 8:18:18 PM10/15/16
to
my test indicates that the order of the 3 tests can impact the results
but that I can create a test where all 3 in sequence take almost exactly
the same time with or without optimization. In any event, the
differences are very small and not likely to be of importance in most cases.

campbel...@gmail.com

unread,
Oct 15, 2016, 9:13:23 PM10/15/16
to
On Sunday, October 16, 2016 at 10:12:00 AM UTC+11, FortranFan wrote:
> On Saturday, October 15, 2016 at 4:03:58 PM UTC-4, Stefano Zaghi wrote:
>
>
> use, intrinsic :: iso_fortran_env, only : I4 => int32, WP => real64
>
> subroutine my_cpu_time( time )
>
> !.. Argument list
> real(WP), intent(inout) :: time
>
> !.. Local variables
> integer(I4) :: tick
> integer(I4) :: rate
>
> call system_clock (tick, rate)
>
> time = real(tick, kind=kind(time) ) / real(rate, kind=kind(time) )
>
> return
>
> end subroutine my_cpu_time

I could not identify the version of the compiler and OS you are using but please re-do the test with I8 => int64 ; integer(I8) :: tick

There are lots of SYSTEM_CLOCK implementations using int32 that don't give adequate precision.

A computed GOTO (...), ikey is always going to be faster than SELECT CASE as CASE has much more general values, but..
1) It is a lot more difficult to maintain/extend code based on GOTO
2) for comparison, you should include the code to scan for ikey
3) What does it matter, when the keyword is read from a file.

Ian Harvey

unread,
Oct 15, 2016, 9:46:14 PM10/15/16
to
Thanks for the example code.

Note that the case construct and if construct options are not equivalent
to the computed goto option.

- When keyword has the value zero (which was perhaps not intentional -
maybe `keyword = int(random*3, int32) + 1` ?) the goto option does work,
while the other tests do not.

- When keyword has the value one, the goto option executes all three
worker subroutines, and when it has the value two, it executes both
`worker2` and `worker3`.

If I change the computed goto option to:

call system_clock(profiling(1), count_rate)
goto (10, 20, 30), keyword
goto 40
10 call worker1(key=keyword, array=key_work) ; goto 40
20 call worker2(key=keyword, array=key_work) ; goto 40
30 call worker3(key=keyword, array=key_work) ; goto 40
40 continue
call system_clock(profiling(2), count_rate)

then I see precious little difference in the results.

From looking at the generated assembly with ifort 17.0's default
command line optimisation on Windows x46, all options are implemented
using straightforward cmp and jxx instructions in pretty much the exact
same way, including the same nominal compiler branch selection
probabilities.

I personally find the case construct and if construct examples far
easier to read. Their use is demonstrably far less error prone too ;).

dpb

unread,
Oct 15, 2016, 9:58:37 PM10/15/16
to
On 10/15/2016 8:45 PM, Ian Harvey wrote:
...

> From looking at the generated assembly with ifort 17.0's default
> command line optimisation on Windows x46, all options are implemented
> using straightforward cmp and jxx instructions in pretty much the exact
> same way, including the same nominal compiler branch selection
> probabilities.
...

That's certainly what I'd expected, and hence that the results will be
also be the same...

Stefano Zaghi

unread,
Oct 16, 2016, 1:27:25 AM10/16/16
to
Dear Gary,

feel free to think whatever you want, but remain the fact that:

1. you did not provide the whole test, thus your is not reproducible => meaningless;
2. you did not try to mimic OP scenario => meaningless;
3. when the performance are "imperative" (I do a lot of HPC for your knowledge) goto are the evil for multi-thread/vectorization (and you compile with optimizations enabled) => your conclusions are wrong.

Dear dpb, I provided the full program, you can check what the optimizer generates, but as Ian checked the Intel optimizer do a great job.

Dear Ian, thank you very much: last night I suspect there was something wrong, but I was too tired to check, my knowledge of goto is near to zero. This is the reasons to public the full tests. I'll update the gist very soon, thank you very much!

Dear FortranFan, you too much kind, but I am not up to "bust" nothing :-) I'll add you test to my gist soon.

My best regards.

Stefano Zaghi

unread,
Oct 16, 2016, 2:02:51 AM10/16/16
to
Dear all,

I have amended the test with Ian's correction (I also changed integer(int32) => integer(int64) for the tic-toc profiling as other suggested). The amended code is here https://gist.github.com/szaghi/3b761e66234a90d4815ad30a4d81354c#benchmark-program

The results is essentially unchanged, see this https://gist.github.com/szaghi/3b761e66234a90d4815ad30a4d81354c#average-performances and this https://gist.github.com/szaghi/3b761e66234a90d4815ad30a4d81354c#benchmarks-output

The 3 branching models behave almost identically.

I added the wise observations of FortranFan here https://gist.github.com/szaghi/3b761e66234a90d4815ad30a4d81354c#conclusions

Please, note the my conclusions are not as sharp as others: "for my test case goto SEEMS to not provide any speedup" is not an absolute sentence like "goto is always faster then select case" that is evidently false, whereas it is true that goto is obsolescent, produces spaghetti-code, is not clear, is not maintainable, prevents HPC exploitation.

My best regards.

James Van Buskirk

unread,
Oct 16, 2016, 2:32:44 AM10/16/16
to
"Ian Harvey" wrote in message news:ntum4h$tto$1...@dont-email.me...

> From looking at the generated assembly with ifort 17.0's default command
> line optimisation on Windows x46, all options are implemented using
> straightforward cmp and jxx instructions in pretty much the exact same
> way, including the same nominal compiler branch selection probabilities.

What I usually do to check compiler output is to put the code in
question in a minimal procedure so that the results are easier to
interpret. Minimal compilable example, what a concept!

D:\gfortran\clf\selecttest>type select.f90
subroutine sub(knt)
implicit none
integer knt
select case(knt)
case(1)
knt = 2
case(2)
knt = 3
case(3)
knt = 1
case(4)
knt = 5
case(5)
knt = 4
end select
end subroutine sub

And an excerpt from the assembly output. Note that I used /O3 as in the
O.P.
All three version indeed seem to do the same thing: first the argument knt
is
loaded into rax and and checked whether it's in range. Then it's moved to
rdx and an address at fixed offset from the jump table is loaded into rax,
after which the result is obtained in rcx and moved into the argument
memory.

D:\gfortran\clf\selecttest>ifort /O3 /c /FA select.f90
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on
Intel(R
) 64, Version 16.0.2.180 Build 20160204
Copyright (C) 1985-2016 Intel Corporation. All rights reserved.

I used
SUB PROC
; parameter 1: rcx
.B1.1:: ; Preds .B1.0
L1::
;1.12
mov r8, rcx ;1.12
movsxd rax, DWORD PTR [r8] ;4.20
dec rax ;4.20
cmp rax, 4 ;4.20
ja .B1.3 ; Prob 50% ;4.20
; LOE rax rbx rbp rsi rdi r8 r12 r13 r14 r15
xmm6 xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15
.B1.2:: ; Preds .B1.1
mov edx, eax ;4.20
lea rax, QWORD PTR [__ImageBase] ;4.20
mov ecx, DWORD PTR
[imagerel(.2.2_2.switchtab.0.0.1)+rax+rdx*4] ;4.20
mov DWORD PTR [r8], ecx ;6.14
; LOE rbx rbp rsi rdi r12 r13 r14 r15 xmm6
xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15
.B1.3:: ; Preds .B1.1 .B1.2
ret ;16.1
ALIGN 16
; LOE
.B1.4::
; mark_end;
SUB ENDP

Here is the jump table:

.2.2_2.switchtab.0.0.1 DD 2
DD 3
DD 1
DD 5
DD 4

D:\gfortran\clf\selecttest>type goto.f90
subroutine sub(knt)
implicit none
integer knt
goto (1,2,3,4,5), knt

1 knt = 2
go to 10
2 knt = 3
go to 10
3 knt = 1
go to 10
4 knt = 5
go to 10
5 knt = 4

10 continue
end subroutine sub

D:\gfortran\clf\selecttest>ifort /O3 /c /FA goto.f90
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on
Intel(R
) 64, Version 16.0.2.180 Build 20160204
Copyright (C) 1985-2016 Intel Corporation. All rights reserved.

Again, the assembly code and jump table:

SUB PROC
; parameter 1: rcx
.B1.1:: ; Preds .B1.0
L1::
;1.12
mov eax, DWORD PTR [rcx] ;4.8
dec eax ;4.8
cmp eax, 4 ;4.8
ja .B1.3 ; Prob 50% ;4.8
; LOE rax rcx rbx rbp rsi rdi r12 r13 r14
r15 xmm6 xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15
.B1.2:: ; Preds .B1.1
lea rdx, QWORD PTR [__ImageBase] ;4.8
mov eax, DWORD PTR
[imagerel(.2.2_2.switchtab.0.0.1)+rdx+rax*4] ;4.8
jmp .B1.4 ; Prob 100% ;4.8
; LOE rcx rbx rbp rsi rdi r12 r13 r14 r15
eax xmm6 xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15
.B1.3:: ; Preds .B1.1
mov eax, 2 ;6.14
; LOE rcx rbx rbp rsi rdi r12 r13 r14 r15
eax xmm6 xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15
.B1.4:: ; Preds .B1.2 .B1.3
mov DWORD PTR [rcx], eax ;6.14
ret ;17.1
ALIGN 16
; LOE
.B1.5::
; mark_end;
SUB ENDP

.2.2_2.switchtab.0.0.1 DD 2
DD 3
DD 1
DD 5
DD 4

D:\gfortran\clf\selecttest>type if.f90
subroutine sub(knt)
implicit none
integer knt
if (knt == 1) then
knt = 2
else if (knt == 2) then
knt = 3
else if (knt == 3) then
knt = 1
else if (knt == 4) then
knt = 5
else if (knt == 5) then
knt = 4
end if
end subroutine sub

D:\gfortran\clf\selecttest>ifort /O3 /c /FA if.f90
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on
Intel(R
) 64, Version 16.0.2.180 Build 20160204
Copyright (C) 1985-2016 Intel Corporation. All rights reserved.

And the assembly code and jump table:

SUB PROC
; parameter 1: rcx
.B1.1:: ; Preds .B1.0
L1::
;1.12
mov r8, rcx ;1.12
mov eax, DWORD PTR [r8] ;4.8
dec eax ;4.16
cmp eax, 4 ;4.16
ja .B1.3 ; Prob 50% ;4.16
; LOE rax rbx rbp rsi rdi r8 r12 r13 r14 r15
xmm6 xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15
.B1.2:: ; Preds .B1.1
lea rdx, QWORD PTR [__ImageBase] ;4.16
mov ecx, DWORD PTR
[imagerel(.2.2_2.switchtab.0.0.1)+rdx+rax*4] ;4.16
mov DWORD PTR [r8], ecx ;5.14
; LOE rbx rbp rsi rdi r12 r13 r14 r15 xmm6
xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15
.B1.3:: ; Preds .B1.1 .B1.2
ret ;15.1
ALIGN 16
; LOE
.B1.4::
; mark_end;
SUB ENDP

.2.2_2.switchtab.0.0.1 DD 2
DD 3
DD 1
DD 5
DD 4

They all look pretty similar to me, so I would surmise that any differences
in timing are artifacts of the timing methodology.

dpb

unread,
Oct 16, 2016, 10:10:09 AM10/16/16
to
On 10/16/2016 12:27 AM, Stefano Zaghi wrote:
...

> Dear dpb, I provided the full program, you can check what the
> optimizer generates, but as Ian checked the Intel optimizer do a
> great job.

...

Chill, dood! :)

Not your manhood being called into question here...just the likelihood
of what a modern optimizer will do with a couple or three different
constructions.

I don't have a recent (Fortran) compiler installed any longer; hence
it's not at all simple for me to generate realistic code to compare. I
was simply conjecturing that _IF_ a given test showed a particular bias
at some point in the past, _perhaps_ that indicated either that compiler
didn't optimize as well (yet) or the options to do so weren't in force
or somesuch. As James Van B posted, in isolation the code generated the
same machine instructions for each of three options (CASE, GOTO, IF).
That being the case (so to speak :) ), the timing must be the same for
that piece of code and so as he notes, anything that shows up
differently must be from other sources.

That there's advantage in source form for SELECT CASE in terms of human
legibility and extension isn't being argued too terribly much altho it's
also quite possible to write very well structured code using GOTO if one
uses discipline in doing so; particularly for such structures as
outlined here; having a common exit makes it pretty simple to lay out
the structure in linear fashion. Where spaghetti code arises is when
there's a much more convoluted logic path imposed in addition so that
execution reverts to an earlier section again or in implementations
where discipline was not maintained and code is scattered around more or
less willy-nilly. This certainly has happened and can happen again, but
isn't _necessarily_ the result of the judicious use of GOTO.

That it would be the first choice I'll grant is somewhat anachronistic,
yes, but recall that the poster of the suggestion is of an age that long
predates the alternate constructions into the language (or much of _any_
language, for that matter) and also based on his postings over the
years, his recent endeavors have continued to use older-vintage machines
and tools that don't necessarily have all the features or optimizations
of modern compilers so that in fact, he may have the case where the GOTO
option _is_ still actually faster because in that particular compiler
the optimization of the later construct may not have yet occurred.
Again, I don't know this, I have that compiler still on another old
machine here but it would take some significant effort to drag it out
and get the necessary peripherals hooked up to test and it's not worth
the effort to do so...

Gary Scott

unread,
Oct 16, 2016, 4:04:24 PM10/16/16
to
On 10/16/2016 12:27 AM, Stefano Zaghi wrote:
I replied with the complete test code with exception of
declarations...the ttvalues are 64 bit reals, the array of clock ticks
are 64 bit integers. The call procedures are wrappers to intel MKL
procedures. They will be obvious. The wrappers do little but provide
some additional "time tag reset" features and features to synchronize to
the real time clock provided by date_and_time. I use that to help
ensure consistency and identify sample glitches caused by OS paging or
cache misses or whatever other interruptions there might be.

In any event, my soffit repair is more important task for this weekend,
before it gets cold out.

I'm fairly convinced that in most cases, the goto will perform nearly
identically to select case/if. I was able to identify a scenario where
it was faster and scenarios where it was slower by roughly 7 ns. That's
in the noise and not consistent, so probably caused by optimizer
oddities or cache behavior differences or you name it.

I did not intend to do anything but toy with this until I was able to
get to work on my repair. I do think that there is a selection behavior
with goto that causes it to occasionally take extra time to select a
path. While most path selections were identical to select case or if,
there was a rare, fairly random case where rather than ~38ns, it took on
the order of 1us. This difference was fairly consistent with computed
goto loop and was never seen with select case or if.

Stefano Zaghi

unread,
Oct 16, 2016, 4:22:12 PM10/16/16
to
Dear dpb,

Il giorno domenica 16 ottobre 2016 16:10:09 UTC+2, dpb ha scritto:
> Chill, dood! :)

Sorry, my English is very limited, slang is not covered at all. I argue this should be something "keep it easy, keep calm...", if so, I am really a piece of ice :-)

> Not your manhood being called into question here...just the likelihood
> of what a modern optimizer will do with a couple or three different
> constructions.

My "manhood" is a matter of my wife. I simply observed that I have provided the full test thus anyone can stop to guess and suppose and conjecture and try his/her compiler of preference, as Ian and James already done. I am really calm, and you?

> I don't have a recent (Fortran) compiler installed any longer; hence
> it's not at all simple for me to generate realistic code to compare. I
> was simply conjecturing that _IF_ a given test showed a particular bias
> at some point in the past, _perhaps_ that indicated either that compiler
> didn't optimize as well (yet) or the options to do so weren't in force
> or somesuch. As James Van B posted, in isolation the code generated the
> same machine instructions for each of three options (CASE, GOTO, IF).
> That being the case (so to speak :) ), the timing must be the same for
> that piece of code and so as he notes, anything that shows up
> differently must be from other sources.

I agree, and I was of the same idea even before the test. My test produces the same timing for all branching, it is the Gary's test that seems to show different bias, but we cannot reproduce it.

> That there's advantage in source form for SELECT CASE in terms of human
> legibility and extension isn't being argued too terribly much altho it's
> also quite possible to write very well structured code using GOTO if one
> uses discipline in doing so; particularly for such structures as
> outlined here; having a common exit makes it pretty simple to lay out
> the structure in linear fashion.

I disagree. Even the very simple goto of Ian is more complicated than the equivalent select case or if elseif construcuts: Ian was very disciplined, but the goto remains unreadable.

> Where spaghetti code arises is when
> there's a much more convoluted logic path imposed in addition so that
> execution reverts to an earlier section again or in implementations
> where discipline was not maintained and code is scattered around more or
> less willy-nilly. This certainly has happened and can happen again, but
> isn't _necessarily_ the result of the judicious use of GOTO.

I disagree. Goto helps just to jump everywhere, disciplined branching can be done with other constructs more sane. Teaching to new coders to use goto is really a bad teaching.

> That it would be the first choice I'll grant is somewhat anachronistic,
> yes, but recall that the poster of the suggestion is of an age that long
> predates the alternate constructions into the language (or much of _any_
> language, for that matter) and also based on his postings over the
> years, his recent endeavors have continued to use older-vintage machines
> and tools that don't necessarily have all the features or optimizations
> of modern compilers so that in fact, he may have the case where the GOTO
> option _is_ still actually faster because in that particular compiler
> the optimization of the later construct may not have yet occurred.

I think I miss the most part of this sentence. However, it seems to me that you are trying to cover all cases, it is just to trying to "climb over a mirror": yes, if you are running an 90' x8086 with f77 sure goto is for you. We are now in 2016 (close to 2017) and hopefully select case and if elseif are well implemented into almost all compilers. Thus, nope, goto nowadays does not offer anything more than select case and if eleif, it is not faster, it is only more error-prone. It is very curios that into the Van Snyder's thread you claimed that my approach flavors "snappy coders" while now all coders are so disciplined that goto is a reliable approach... funny.

> Again, I don't know this, I have that compiler still on another old
> machine here but it would take some significant effort to drag it out
> and get the necessary peripherals hooked up to test and it's not worth
> the effort to do so...

Ian and James shown that the Intel and GNU do a good job for all the 3 branching models. If you need other tests I can try to complete them, if I'll be up to the task.

My best regards.

campbel...@gmail.com

unread,
Oct 16, 2016, 8:51:29 PM10/16/16
to
On Monday, October 17, 2016 at 7:22:12 AM UTC+11, Stefano Zaghi wrote:
>
> I disagree. Even the very simple goto of Ian is more complicated than the equivalent select case or if elseif construcuts: Ian was very disciplined, but the goto remains unreadable.
>
I see no difference between SELECT CASE and GOTO coding structure, and I would suggest that the compiler would make the GOTO a worse case. All this adverse talk about GOTO is unnecessary bias. I find the following easy to read.

subroutine s_cgt( ikey, n, r )

integer, intent(in) :: ikey
integer, intent(in) :: n
real(WP), intent(inout) :: r

goto (1,2,3,4,5,6,7,8,9,10), ikey

call s_error (ikey)
go to 99

1 call s1( n, r )
go to 99

2 call s2( n, r )
go to 99

3 call s3( n, r )
go to 99

4 call s4( n, r )
go to 99

5 call s5( n, r )
go to 99

6 call s6( n, r )
go to 99

7 call s8( n, r )
go to 99

8 call s8( n, r )
go to 99

9 call s9( n, r )
go to 99

10 call s10( n, r )
go to 99

99 return

end subroutine s_cgt

campbel...@gmail.com

unread,
Oct 16, 2016, 8:54:38 PM10/16/16
to
On Monday, October 17, 2016 at 11:51:29 AM UTC+11, campbel...@gmail.com wrote:
> I see no difference between SELECT CASE and GOTO coding structure, and I would suggest that the compiler would make the GOTO a worse case. All this adverse talk about GOTO is unnecessary bias. I find the following easy to read.
>
Why can't we edit posts !!

I meant to say : that the compiler would NOT make the GOTO a worse case

Ian Harvey

unread,
Oct 16, 2016, 11:12:46 PM10/16/16
to
On 2016-10-17 11:51, campbel...@gmail.com wrote:
> On Monday, October 17, 2016 at 7:22:12 AM UTC+11, Stefano Zaghi
> wrote:
>>
>> I disagree. Even the very simple goto of Ian is more complicated
>> than the equivalent select case or if elseif construcuts: Ian was
>> very disciplined, but the goto remains unreadable.
>>
> I see no difference between SELECT CASE and GOTO coding structure,
> and I would suggest that the compiler would make the GOTO a worse
> case. All this adverse talk about GOTO is unnecessary bias. I find
> the following easy to read.
>
> subroutine s_cgt( ikey, n, r )
>
> integer, intent(in) :: ikey integer, intent(in) ::
> n real(WP), intent(inout) :: r
>
> goto (1,2,3,4,5,6,7,8,9,10), ikey

I read the above statement, and it tells me that execution is going
somewhere, based on the value of ikey. It tells me nothing about why
execution is branching, or the nature of the branch.

(You knew when you wrote that statement the why and what, but will the
person who has to maintain this code (even if it is still you), know
tomorrow?)

On the other hand,

select case (ikey)

tells me that different _blocks of code_ are about to about to be
executed, based on the value of ikey.

The semantics of SELECT CASE are a better fit to the story that the
source code is trying to tell.

(This is the same reasoning I use in preferring a case construct over
sequential if constructs for this scenario - I read "select case", I
know I am selecting a case based on a single value, while "if ..." just
tells me conditional execution - I need to look at all the subsequent
tests to work out what is going on.)

Similar clarity of code comments apply to the notional blocks below.
For example, the delineation of the blocks isn't anywhere as distinct as
the explicit block syntax of select case - you need to read ahead to
figure out that any one goto to label 99 effectively means "leave the
construct", you need to confirm that goto is present in all blocks, and
you may need to consider the possibility of jumps into the construct
from elsewhere. I also find the labelling of the condition that
triggers the entry into the block far more indirect - if two such
constructs are required in the same inclusive scope then some sort of
label offset will be required (be careful to not mix up the sets),
labels in the list are not required to be unique, if you happen to miss
a label in the list the compiler isn't going to care, and the same block
of code can be addressed by multiple labels.

It is far clearer to have the structural blocks of code delineated by
structural syntax, rather than them being inferred.

Why didn't s7 get some love?

Stefano Zaghi

unread,
Oct 16, 2016, 11:35:37 PM10/16/16
to
Dear Campbel,
We are passed to say "GOTO is always compiled into a faster branching" to "the compiler would NOT make the goto a worse case"... funny.

I simply replied to whom suggested to use goto instead select case because goto is faster: this is a false myth (that could be true in old-good days that select case was born, but not now, and we are leaving now not in the past), and there are many good things to avoid goto.

You could think that goto is wonderful, but it is your reality, I think it does not, so for me it is necessary to point it out, really it is not uncessary talk. As Ian as replied, goto is not really readable, it is error-prone, it is spaghetti-code-prone, it prevents multi-treading, it is an obsolescent feature.

My best regards.

Stefano Zaghi

unread,
Oct 17, 2016, 12:11:04 AM10/17/16
to
Dear Gary,

Il giorno domenica 16 ottobre 2016 22:04:24 UTC+2, Gary Scott ha scritto:
> I replied with the complete test code with exception of
> declarations...the ttvalues are 64 bit reals, the array of clock ticks
> are 64 bit integers. The call procedures are wrappers to intel MKL
> procedures. They will be obvious. The wrappers do little but provide
> some additional "time tag reset" features and features to synchronize to
> the real time clock provided by date_and_time. I use that to help
> ensure consistency and identify sample glitches caused by OS paging or
> cache misses or whatever other interruptions there might be.

I am sorry, I missed the whole program, my bad, mea culpa. Anyhow, you have used almost the same number of lines to describe the "exceptions or missed lines" as the lines of statement you have actually posted... can you re-post "all" the program for me thus I can easily (cut/paste) reproduce "exactly" your test? I am sorry, but the interpretation of your "exceptions description" could let me to generate a different test.

> In any event, my soffit repair is more important task for this weekend,
> before it gets cold out.

Good luck for your "soffit".

> I'm fairly convinced that in most cases, the goto will perform nearly
> identically to select case/if. I was able to identify a scenario where
> it was faster and scenarios where it was slower by roughly 7 ns.

Well, until I can reproduce exactly your test, I suspect that you have identified nothing. 7ns respect what?

> That's
> in the noise and not consistent, so probably caused by optimizer
> oddities or cache behavior differences or you name it.

Probably, I agree.

> I did not intend to do anything but toy with this until I was able to
> get to work on my repair. I do think that there is a selection behavior
> with goto that causes it to occasionally take extra time to select a
> path. While most path selections were identical to select case or if,
> there was a rare, fairly random case where rather than ~38ns, it took on
> the order of 1us. This difference was fairly consistent with computed
> goto loop and was never seen with select case or if.

I am sorry, but I am going to be lost. You have stated that goto plays a role when "performance is imperative", now it seems the contrary. Probably I have missed some new results arising from your test. Does, in your test(s), goto taking extra time? Indeed, I would bet that the 3 branching models have the same performance (in my opinion, talking about 38ns or similar measures is meaningless if not accurately contextualized).

If you agree that there is not a relevant speedup in the usage of goto, why one should use it nowadays?

My best regards.

FortranFan

unread,
Oct 17, 2016, 1:15:35 AM10/17/16
to
On Sunday, October 16, 2016 at 11:12:46 PM UTC-4, Ian Harvey wrote:

> On 2016-10-17 11:51, campbelljohn wrote:
> .. I find
> > the following easy to read.
> >
> > subroutine s_cgt( ikey, n, r )
> >
> > integer, intent(in) :: ikey integer, intent(in) ::
> > n real(WP), intent(inout) :: r
> >
> > goto (1,2,3,4,5,6,7,8,9,10), ikey
>
> .. You knew when you wrote that statement the why and what, but will the
> person who has to maintain this code (even if it is still you), know
> tomorrow?..
>

Another point to keep in mind is one I have mentioned several times before on this forum: in our experience, the few young engineers and scientists who are coming to Fortran often have backgrounds in other coding approaches such as MATLAB, Visual Basic, C/C++ etc. That is, Fortran is often NOT their first choice for a programming language. These other languages have "switch" and "Select Case" constructs which do have some *commonality* with "select case" in Fortran; please note I'm not trying to ignore the differences between these languages themselves or with Fortran (thus there is no need to further diverge the thread on this account), I'm simply bringing up aspects that help young coders pick up a new language more easily: SELECT CASE in Fortran happens to be one of them. In fact, I do recall a project where a young engineer in mid-20s in the team had lots of issues fixing and extending code that made extensive use of computed GOTOs: this person with good background in MATLAB and Visual Basic .NET simply couldn't relate to computed GOTO. The code in this project is one of the few still left with older style in this organization i.e., fixed format with constructs ranging from FORTRAN IV to 66/77 with some DEC extensions mainly due to the approach by a 3rd party simulation package that is involved, one that Ian Harvey seems to have experience with, one whose first name is a popular ski area in western US!

https://www.mathworks.com/help/matlab/ref/switch.html?requestedDomain=www.mathworks.com
https://msdn.microsoft.com/en-us/library/cy37t14y.aspx


> Why didn't s7 get some love?
>
> ..

Good point! Looks like I snuck in the vicious discrimination against this poor sub that went under John Campbell's radar.

FortranFan

unread,
Oct 17, 2016, 1:44:01 AM10/17/16
to
On Sunday, October 16, 2016 at 10:10:09 AM UTC-4, dpb wrote:

> .. recall that the poster of the suggestion is of an age that long
> predates the alternate constructions into the language (or much of _any_
> language, for that matter) and also based on his postings over the
> years, his recent endeavors have continued to use older-vintage machines
> and tools that don't necessarily have all the features or optimizations
> of modern compilers so that in fact, he may have the case where the GOTO
> option _is_ still actually faster because in that particular compiler
> the optimization of the later construct may not have yet occurred.
> Again, I don't know this ..


@dpb,

Look upthread - several requests were made to said poster to provide some details but there has been no response yet. And notice below further information and request is extended to this enlighten us.

@Terence/FJ,
If you are still following this, it will be helpful if you can explain the provide some actionable evidence to back up your comment, "I still prefer a computed GOTO over CASE anyway, since this is usually compiled as a faster selection." and "I did such benchmark few years ago ... and Terence is right !"

Terence, I do recall reading you use Compaq Visual Fortran (published circa 2001?) on some of your "older-vintage machines" and if so, please note I have tried my test case with Compaq Visual Fortran 6.6a and again I do NOT see any performance difference with /O2 optimization option. You can take the test code and report what you see. Note the CPU performance timing results are mainly the CPU demand of the keyword-processing subroutines - if these procedures are trivial, chances are in actual code users will fail to notice anything but if the procedures are very CPU intensive, the use of computed GOTO is not going to help any - it will be the kind of "premature optimization" Knuth decried. So please explain.

N.B.: do NOT define a preprocessor directive of IFORT if you are using Compaq Visual Fortran; the code below uses such a directive to work with the two compilers.

Upon execution on Windows 7 OS, Intel i5 CPU, 2.7 GHz with 8 GB RAM:
-- begin output --
Mythbuster #1: SELECT CASE vs COMPUTED GOTO

SELECT CASE:
Trial 1
CPU Time: 3.999948501586914E-03 seconds.
Trial 2
CPU Time: 5.000114440917969E-03 seconds.
Trial 3
CPU Time: 3.999948501586914E-03 seconds.
Trial 4
CPU Time: 3.000020980834961E-03 seconds.
Trial 5
CPU Time: 4.000186920166016E-03 seconds.
Trial 6
CPU Time: 3.999948501586914E-03 seconds.
Trial 7
CPU Time: 3.999948501586914E-03 seconds.
Trial 8
CPU Time: 4.000186920166016E-03 seconds.
Trial 9
CPU Time: 3.999948501586914E-03 seconds.
Trial 10
CPU Time: 3.000020980834961E-03 seconds.
COMPUTED GOTO:
Trial 1
CPU Time: 4.000186920166016E-03 seconds.
Trial 2
CPU Time: 3.999948501586914E-03 seconds.
Trial 3
CPU Time: 3.999948501586914E-03 seconds.
Trial 4
CPU Time: 2.999782562255859E-03 seconds.
Trial 5
CPU Time: 3.999948501586914E-03 seconds.
Trial 6
CPU Time: 4.000186920166016E-03 seconds.
Trial 7
CPU Time: 3.999948501586914E-03 seconds.
Trial 8
CPU Time: 3.999948501586914E-03 seconds.
Trial 9
CPU Time: 2.999782562255859E-03 seconds.
Trial 10
CPU Time: 3.999948501586914E-03 seconds.
SELECT CASE: Average CPU Time 3.875017166137695E-03 seconds.
COMPUTED GOTO: Average CPU Time 3.874957561492920E-03 seconds.
Press any key to continue
-- end output --

Here's the full test case:
-- begin code --
module mykinds_m

!dec$ if defined (IFORT)

use, intrinsic :: iso_fortran_env, only : I4 => int32, I8 => int64, WP => real64

implicit none

!dec$ else

implicit none

integer, parameter :: I8 = selected_int_kind(10)
integer, parameter :: I4 = selected_int_kind(9)
integer, parameter :: WP = selected_real_kind(15,307)

!dec$ endif

real(WP), parameter :: ZERO = 0.0_wp

end module mykinds_m

module procs_m

use mykinds_m, only : WP, ZERO

implicit none

contains

subroutine s1( n, r )

include "i.f90"

end subroutine s1

subroutine s2( n, r )

include "i.f90"

end subroutine s2

subroutine s3( n, r )

include "i.f90"

end subroutine s3

subroutine s4( n, r )

include "i.f90"

end subroutine s4

subroutine s5( n, r )

include "i.f90"

end subroutine s5

subroutine s6( n, r )

include "i.f90"

end subroutine s6

subroutine s7( n, r )

include "i.f90"

end subroutine s7

subroutine s8( n, r )

include "i.f90"

end subroutine s8

subroutine s9( n, r )

include "i.f90"

end subroutine s9

subroutine s10( n, r )

include "i.f90"

end subroutine s10

end module procs_m

module m

use procs_m

implicit none

private

!dec$ if defined (IFORT)
character(len=*), parameter, public :: keywords(*) = [ character(len=3) :: "s1", "s2", "s3", &
"s4", "s5", "s6", "s7", "s8", "s9", "s10" ]
integer, parameter, public :: ikeys(*) = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
!dec$ else
integer, parameter :: MAXKEYS = 10
character(len=3), parameter, public :: keywords(MAXKEYS) = [ "s1 ", "s2 ", "s3 ", &
"s4 ", "s5 ", "s6 ", "s7 ", "s8 ", "s9 ", "s10" ]
integer, parameter, public :: ikeys(MAXKEYS) = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
!dec$ endif

public :: s_slc
public :: s_cgt

contains

subroutine s_slc( keyword, n, r )

character(len=*), intent(in) :: keyword
integer, intent(in) :: n
real(WP), intent(inout) :: r

select case ( keyword )

case ( keywords(1) )

call s1( n, r )

case ( keywords(2) )

call s2( n, r)

case ( keywords(3) )

call s3( n, r)

case ( keywords(4) )

call s4( n, r)

case ( keywords(5) )

call s5( n, r)

case ( keywords(6) )

call s6( n, r)

case ( keywords(7) )

call s7( n, r)

case ( keywords(8) )

call s8( n, r)

case ( keywords(9) )

call s9( n, r)

case ( keywords(10) )

call s10( n, r)

case default

print *, "s: invarid keyword of ", keyword
return

end select

return

end subroutine s_slc

subroutine s_cgt( ikey, n, r )

integer, intent(in) :: ikey
integer, intent(in) :: n
real(WP), intent(inout) :: r

goto (1,2,3,4,5,6,7,8,9,10), ikey

1 continue
call s1( n, r )
go to 99

2 continue
call s2( n, r )
go to 99

3 continue
call s3( n, r )
go to 99

4 continue
call s4( n, r )
go to 99

5 continue
call s5( n, r )
go to 99

6 continue
call s6( n, r )
go to 99

7 continue
call s7( n, r )
go to 99

8 continue
call s8( n, r )
go to 99

9 continue
call s9( n, r )
go to 99

10 continue
call s10( n, r )
go to 99 ! wonder if compiler optimization eliminates this

99 continue
return

end subroutine s_cgt

end module m

module cpu_m

use mykinds_m, only : IP => I8, WP

implicit none

contains

subroutine my_cpu_time( time )

!.. Argument list
real(WP), intent(inout) :: time

!.. Local variables
integer(IP) :: tick
integer(IP) :: rate

call system_clock (tick, rate)

time = real(tick, kind=kind(time) ) / real(rate, kind=kind(time) )

return

end subroutine my_cpu_time

end module cpu_m
! include i.f90

!.. Argument list
integer, intent(in) :: n
real(WP), intent(inout) :: r

!.. Local variables
integer :: v_size
integer :: istat
real(WP), allocatable :: v(:)

v_size = 2**( min(n,10) )
allocate( v(v_size), stat=istat )
if ( istat /= 0 ) then
print *, ": allocation of v failed: v_size, stat = ", v_size, istat
stop
end if

call random_number( v )

!dec$ if defined (IFORT)
r = norm2( v )
!dec$ else
r = sqrt( dot_product(v, v)/real(v_size, kind=kind(r)) )
!dec$ endif

deallocate( v, stat=istat )

return

! main program
program p

use mykinds_m, only : WP, ZERO
use m, only : s_slc, s_cgt, keywords
use cpu_m, only : my_cpu_time

implicit none

!..
integer, parameter :: MAXREPEAT = 10
integer, parameter :: MAXTRIAL = 2**10
integer :: Idx(MAXTRIAL)
integer :: Counter
integer :: j
real(WP) :: Start_Time = ZERO
real(WP) :: End_Time = ZERO
real(WP) :: Ave_Time = ZERO
real(WP) :: CpuTimes_SLC(MAXREPEAT)
real(WP) :: CpuTimes_CGT(MAXREPEAT)
real(WP) :: r(MAXTRIAL)
real(WP) :: x_norm
!dec$ if defined (IFORT)
character(len=*), parameter :: FMT_CPU = "(a, t40, g0, a)"
!dec$ else
character(len=22), parameter :: FMT_CPU = "(A, T40, 1PG22.15, A)"
!dec$ end if

print *, "Mythbuster #1: SELECT CASE vs COMPUTED GOTO"
print *
end program p
-- end code --

FortranFan

unread,
Oct 17, 2016, 1:50:50 AM10/17/16
to
On Saturday, October 15, 2016 at 9:13:23 PM UTC-4, campbel...@gmail.com wrote:

> ..
>
> I could not identify the version of the compiler and OS you are using but please re-do the test with I8 => int64 ; integer(I8) :: tick ..
>

@John Campbell,

Note "Upon execution with Intel Fortran with /O2 on a Windows 7 laptop, Intel i5 CPU 2.7 GHz, 8 GB machine" - I should have added compiler 17.0. Note I have posted the full code, so anyone can try it for themselves if they were so compelled.

I tried as you suggested with int64 as the integer type for tick actual argument in system_clock routine, but it made no discernible difference with the case I presented. But thanks much, I can see how it will help in other cases.


Stefano Zaghi

unread,
Oct 17, 2016, 8:48:56 AM10/17/16
to
Dedicated to FortranFan

https://github.com/szaghi/DEFY

"DEmystify Fortran mYths"

A collections of Fortran Myths that are demystified or confirmed, at least discussed.

My best regards.

Gary Scott

unread,
Oct 17, 2016, 9:25:20 AM10/17/16
to
No, I did not say that. I said that >>IF<< goto showed some performance
advantage and that advantage was important to the problem at hand, I
would not hesitate to use it. However, I would perform enough testing
to determine that was the case before using it.

FortranFan

unread,
Oct 17, 2016, 9:35:14 AM10/17/16
to
:-)))

Mighty cheers, to all the fans out there of 'modern Fortran'!!!

Stefano Zaghi

unread,
Oct 17, 2016, 9:36:31 AM10/17/16
to
Dear Gary,

Il giorno lunedì 17 ottobre 2016 15:25:20 UTC+2, Gary Scott ha scritto:
> No, I did not say that. I said that >>IF<< goto showed some performance
> advantage and that advantage was important to the problem at hand, I
> would not hesitate to use it. However, I would perform enough testing
> to determine that was the case before using it.

I am very sorry, in my bad English the sentence "plays a role" is just another ways to say "if goto shows some performance advantage" when "performance is imperative"...

Assuming that your (not reproducible for us) test shows that goto is faster (on average) says about 5%, do you hesitate or not to use it? Will you use goto even if it prevents further optimizations (multi-threading, vectorization)? Will you use goto even if it makes the code unreadable, un-maintainable? Will you use goto even if it is claimed to be obsolescent? This is the real point, not your 7ns of (presupposed) speedup.

My best regards.

FortranFan

unread,
Oct 17, 2016, 9:41:19 AM10/17/16
to
On Sunday, October 16, 2016 at 4:04:24 PM UTC-4, Gary Scott wrote:

> .. I was able to identify a scenario where
> it was faster and scenarios where it was slower by roughly 7 ns. ..


@Gary Scott,

I am very curious to learn how you can accomplish CPU time measurements reliably with the kind of precision you state, on the order of ns (I assume nanoseconds). Can you please explain how you do this?

dpb

unread,
Oct 17, 2016, 10:00:17 AM10/17/16
to
On 10/17/2016 8:36 AM, Stefano Zaghi wrote:
...

> Assuming that your (not reproducible for us) test shows that goto is
> faster (on average) says about 5%, do you hesitate or not to use it?
> Will you use goto even if it prevents further optimizations
> (multi-threading, vectorization)? Will you use goto even if it makes the
> code unreadable, un-maintainable? Will you use goto even if it is
> claimed to be obsolescent? This is the real point, not your 7ns of
> (presupposed) speedup.

You're fixating on a single benchmark result and ignoring the (even
emphasized) suppositional _IF_ postulates of the response. It was
indicated "YES", under a specific set of circumstances which would
likely (I'm inferring and/or amplifying here) include a limited hardware
environment, possibly even a realtime one with time constraints in a
very controlled situation where inputs are known a priori to be within
some specific set of conditions.

Also, he emphasized he would have done significant testing of the result
to confirm it indeed did have enough of a performance advantage to make
it worth the possible negatives of there being somewhat less readable
code in source form or even that it might take a little more effort to
extend the code in the future if that were to become necessary. These
decisions clearly would not be made lightly but given the constraints
around the specific problem, judged to be worth the tradeoffs.

It says nothing that somewhere else (possibly eve in the same
application where the timing weren't so critical, say) that he wouldn't
use "modern" constructs for the precise reasons you're supporting them
so strongly.

The point being made is there can always be specific circumstances that
justify specific choices that are contrary to what may otherwise be
considered "best practice" in a general software development sense.

I'd again point out that in replacing SELECT CASE with computed GOTO
it's generally NOT at all difficult to prevent spaghetti code as has
been illustrated. Other than there being a need to segregate a group of
line numbers to allow for potential insertion of additional cases, it's
pretty much a "piece-o'-cake" to simply put code blocks inline or call
routines with a single exit point of the overall construct; very little
different, in actual fact, of the other choice with the exception of the
explicit CASE statements (which, of course, can always be incorporated
as comments to ease the code scanning in complex cases)

Stefano Zaghi

unread,
Oct 17, 2016, 10:42:18 AM10/17/16
to
Dear dpb,

Il giorno lunedì 17 ottobre 2016 16:00:17 UTC+2, dpb ha scritto:
> You're fixating on a single benchmark result and ignoring the (even
> emphasized) suppositional _IF_ postulates of the response. It was
> indicated "YES", under a specific set of circumstances which would
> likely (I'm inferring and/or amplifying here) include a limited hardware
> environment, possibly even a realtime one with time constraints in a
> very controlled situation where inputs are known a priori to be within
> some specific set of conditions.

It is funny that you reply for Gary, maybe you can reply also to my previous post for you.

Anyhow, I am not "fixated" on nothing. You are again say a "false myth concerning me": I do not thrust even in my own test, why you can say "I am fixating on the result of 1 test"? Really a silly sentence. I simply report what I learn on many good book and I learn from some good coders: goto is obsolescent for many good reasons.

In my last post to Gary I simply assumed that his test indicates a 5% speedup for goto and asked if in that scenario he hesitate or not to use goto, this is just a confirm for me-donkey-student. What it the matter with you? Your noise about real-time-constraints is very OT. We start comparing goto with select case...

> Also, he emphasized he would have done significant testing of the result
> to confirm it indeed did have enough of a performance advantage to make
> it worth the possible negatives of there being somewhat less readable
> code in source form or even that it might take a little more effort to
> extend the code in the future if that were to become necessary. These
> decisions clearly would not be made lightly but given the constraints
> around the specific problem, judged to be worth the tradeoffs.

So, you argued a lot, and I cannot ask for the complete test to reproduce it?

> It says nothing that somewhere else (possibly eve in the same
> application where the timing weren't so critical, say) that he wouldn't
> use "modern" constructs for the precise reasons you're supporting them
> so strongly.

I simply stated that "when" timing is so critical (that is the main reason adduced by Terence and Co. to promote goto) goto is not good, it preventing multi-threading for example. What it is the matter with you?

> The point being made is there can always be specific circumstances that
> justify specific choices that are contrary to what may otherwise be
> considered "best practice" in a general software development sense.

Well, show me when/where goto is preferable, I will be very happy to learn new things and add it to my collections. Really, teach me a where I would like to use goto.

As you teaching me, we should focus on the poster, and for what we know now, in the OP scenario goto is bad. What is the matter with you?

> I'd again point out that in replacing SELECT CASE with computed GOTO
> it's generally NOT at all difficult to prevent spaghetti code as has
> been illustrated.

I am not up to the task to reply better than Ian's answer, re-read it for a clear understanding why goto-branching is unreadable and unmaintainable.

I simply obsever that "when it flavors your point I have to stick on the most reliable approach (i.e. avoid auto-scaling of m-km), but when it does not there is not generally any difficult to use goto to avoid spaghetti code"... funny, or we live alternatively into a world of very-disciplined-coders or snappy-ones depending if the day is even or odd.

> Other than there being a need to segregate a group of
> line numbers to allow for potential insertion of additional cases, it's
> pretty much a "piece-o'-cake" to simply put code blocks inline or call
> routines with a single exit point of the overall construct; very little
> different, in actual fact, of the other choice with the exception of the
> explicit CASE statements (which, of course, can always be incorporated
> as comments to ease the code scanning in complex cases)

"very little different...", someone told to me "that differences could be little, nevertheless fundamental". Goto allows to jump everywhere, you are assuming-guessing-betting that the coder is really disciplined...

Can I ask you to show me one case where goto is better than select case or if elesif? Just to improve my poor knowledge.

My best regards.

Pascal

unread,
Oct 17, 2016, 11:10:17 AM10/17/16
to
On 13/10/2016 19:42, Richard Maine wrote:
> FJ <francois.jacq@invalid> wrote:
>
>> Most often, the speedup does not matter. And a "select case" construct is
>> easier to extend.
>
> Indeed the OP mentioned nothing about speed, and considering that it is
> used to select a procedure to call, it seems unlikely that the speed of
> the selection would be significant compared to the overhead of the
> subroutine calls unless they were the most trivial of inlineable
> subroutines, which doesn't seem likely from the problem description.
> Seems to me that speed is likely to be very low on the list of concerns
> here, far behind things like clarity, extensibility, etc., which were
> the things the OP asked about.

I did not expect to unsleash so much passion :)

To answer the question, you are right, peed is not my concern is this
case. It is a little piece of software that convert a file in a a format
to an other format. So in effect, it is just used once when the program
is started.

To be honest, python would be more suited for this kind of stuff but on
windows I don't expect python to be present and including a python
interpreter in our project is out of the question at the moment.

Pascal

FortranFan

unread,
Oct 17, 2016, 11:38:07 AM10/17/16
to
On Monday, October 17, 2016 at 10:00:17 AM UTC-4, dpb wrote:

> On 10/17/2016 8:36 AM, Stefano Zaghi wrote:
> ...
>
> > Assuming that your (not reproducible for us) test shows that goto is
> > faster (on average) says about 5%, ..
>
> You're fixating on a single benchmark result ..
>
> Also, he emphasized he would have done significant testing of the result
> to confirm it indeed ..
>
> ..
>
> The point being made is there can always be specific circumstances that
> justify specific choices that are contrary to what may otherwise be
> considered "best practice" in a general software development sense.
>
> I'd again point out that in replacing SELECT CASE with computed GOTO
> it's generally NOT at all difficult to prevent spaghetti code as has
> been illustrated. ..


Hello Stefano,

From one 'modern Fortran' enthusiast to another: please note

* you may want to take a pause and see whether you too have to come to a "fork in the road" [https://en.wikipedia.org/wiki/Fork_in_the_road_(metaphor)] on this forum, regarding how to approach certain attitudes that pop up ever so often. As to whether you really want to join "my club" of being in "kill files" or worse, or if you want to 'play nice' and follow certain unwritten netiquette and as a consequence, let this matter drop!!

* I too have deep concerns, just like you, about the kind of posts:

a) no reproducible test case,

b) code snippets with missing declarations that make them practically worthless,

c) missing details on how timing studies are performed which further impart them as suspicious,

d) missing details on any statistical sampling that should make one question even more strongly about the validity of the results presented. For example, you will notice in the code I posted, the CPU timing is based on SYSTEM_CLOCK intrinsic with care taken, per John Campbell's sound advice on the integer kind precision on the TICK count, with MAXTRIAL (a named constant set to 2**10, can be changed easily by any tester), attempts of the action being measured and the same process is attemped MAXREPEAT (times and finally the mean is taken with the best and worst results excluded. I'm not saying this is the best way, but hey, at least I made an effort. Gary Scott is not revealing any details of his sampling.

e) Reports of timing results in ns (is it nanoseconds?!) should make one doubt even more strong the objectivity of the reporting. The code snippet, as shown by Gary Scott, seems to measure CPU times for a single block construct that effectively has only an integer assignment (knt = xx) - how it even possible using standard Fortran to profile this? I suspect Gary Scott might be using some home-grown/3rd party/proprietary utility to count ticks, but to me that is not all acceptable in a public setting, any performance benchmark has to based on either standard features such as system_clock or a FOSS option.

I don't know what dpb is up to, but I think you too realize what is going on:

1) Terence effectively made a "blanket statement" [https://www.quora.com/What-is-a-blanket-statement] and has not followed up thus far.

2) Unless FJ follows up further, his comment can best be described as a "hit-and-run posting" [https://en.wikipedia.org/wiki/Hit-and-run_posting]

3) Gary Scott posted some results which, to us at least, are highly suspect as explained above, they do not appear scientific or rigorous in the least possible way, pending further disclosure. Anyone reading of them can misuse to propagate their own biases which is my concern.

This is HIGHLY BOTHERSOME to me because the approaches and attitudes displayed in 1), 2) and 3) above seriously hurt the practice of Fortran more than anything else, they simply allow Fortran to be caught in this eternal vortex of biases and myths and perhaps even ineptitude.

Just like you, I too am more than open and willing to learn from coding practices that have been alluded to here as being robust and successful, but there has to be an effort to ENCODE them appropriately for the benefit of succeeding generations, kinda like further variations on the "Numerical Recipes" book or "Design Patterns" by the Gang of Four, you know. But if no such initiative is forthcoming, then in its absence all we can do is question and challenge such stuff, and challenge we must vigorously.

Cheers,

FortranFan

unread,
Oct 17, 2016, 12:02:01 PM10/17/16
to
On Monday, October 17, 2016 at 11:10:17 AM UTC-4, Pascal wrote:

> ..
>
> To answer the question, you are right, peed is not my concern is this
> case. It is a little piece of software that convert a file in a a format
> to an other format. So in effect, it is just used once when the program
> is started.
>
> To be honest, python would be more suited for this kind of stuff ..


@Pascal,

One is "free" (relatively speaking!) to do as one wishes on the cyberspace, but if you are to able to, please note the following:

1) The next time you post something, please make clear your thoughts and intent in the original postitself.

2) When performance/speed is not important, please state so upfront. Fortranners are rather *anal* about this and as you can see, some are prone to sacrifice a lot for alleged "nanoseconds" in performance benefit and will then suggest that to all others as the ultimate truth!!

3) Please refrain from things such as "I am wondering if there is an easier way.", that's too vague on a Fortran forum.

4) When you're the OP, please followup promptly on replies and comments and clarify matters quickly, don't leave the thread hanging and divergent for too long.

5) If your intent and aptitude is for things like Python, mention it upfront. Python is a high-level interpreted language that does NOT even have a switch/select case construct because, with high level abstractions, it offers stuff such as dictionaries which make many built-in programming language features superfluous. So there is little by way of comparison with a compiled language as old as Fortran, if you are thinking of an "easier way". If you're inclined toward a Python-type of approach, I feel you should have posed your original question quite differently.

And that's my opinion,


Stefano Zaghi

unread,
Oct 17, 2016, 12:07:34 PM10/17/16
to
Dear FortranFan,

Il giorno lunedì 17 ottobre 2016 17:38:07 UTC+2, FortranFan ha scritto:
> Hello Stefano,
>
> From one 'modern Fortran' enthusiast to another: please note

I would like to say "to an enthusiast student": mine is only curiosity to learn.


> * you may want to take a pause and see whether you too have to come to a "fork in the road" [https://en.wikipedia.org/wiki/Fork_in_the_road_(metaphor)] on this forum, regarding how to approach certain attitudes that pop up ever so often. As to whether you really want to join "my club" of being in "kill files" or worse, or if you want to 'play nice' and follow certain unwritten netiquette and as a consequence, let this matter drop!!

:-)

My soul is to be kind with "stranger" and to be "more kind with harsh stranger". The allusion to my "manhood" is really a harsh comment that merits and harsh reply, but I tried to be ironic and not in "kill files", thus maybe I cannot be considered in "your club". However, I follow your teachings with great interest and respect.

> * I too have deep concerns, just like you, about the kind of posts:
>
> a) no reproducible test case,
>
> b) code snippets with missing declarations that make them practically worthless,
>
> c) missing details on how timing studies are performed which further impart them as suspicious,
>
> d) missing details on any statistical sampling that should make one question even more strongly about the validity of the results presented. For example, you will notice in the code I posted, the CPU timing is based on SYSTEM_CLOCK intrinsic with care taken, per John Campbell's sound advice on the integer kind precision on the TICK count, with MAXTRIAL (a named constant set to 2**10, can be changed easily by any tester), attempts of the action being measured and the same process is attemped MAXREPEAT (times and finally the mean is taken with the best and worst results excluded. I'm not saying this is the best way, but hey, at least I made an effort. Gary Scott is not revealing any details of his sampling.
>
> e) Reports of timing results in ns (is it nanoseconds?!) should make one doubt even more strong the objectivity of the reporting. The code snippet, as shown by Gary Scott, seems to measure CPU times for a single block construct that effectively has only an integer assignment (knt = xx) - how it even possible using standard Fortran to profile this? I suspect Gary Scott might be using some home-grown/3rd party/proprietary utility to count ticks, but to me that is not all acceptable in a public setting, any performance benchmark has to based on either standard features such as system_clock or a FOSS option.

I agree, especially concerning tests: to be of some usefulness, a test must be highly reproducible.

> I don't know what dpb is up to, but I think you too realize what is going on:
>
> 1) Terence effectively made a "blanket statement" [https://www.quora.com/What-is-a-blanket-statement] and has not followed up thus far.
>
> 2) Unless FJ follows up further, his comment can best be described as a "hit-and-run posting" [https://en.wikipedia.org/wiki/Hit-and-run_posting]
>
> 3) Gary Scott posted some results which, to us at least, are highly suspect as explained above, they do not appear scientific or rigorous in the least possible way, pending further disclosure. Anyone reading of them can misuse to propagate their own biases which is my concern.

I was not so analytic, but my feeling was similar: I simply replied to the sharp sentence of Terence, nope, goto is not always or even generally compiled into a faster selector, really simple. Now we are talking about "real-time-constrains"... If someone really want to talk about performance when goto is concerned, it is surprising that omits that the multi-threading is prevented...

> Just like you, I too am more than open and willing to learn from coding practices that have been alluded to here as being robust and successful, but there has to be an effort to ENCODE them appropriately for the benefit of succeeding generations, kinda like further variations on the "Numerical Recipes" book or "Design Patterns" by the Gang of Four, you know. But if no such initiative is forthcoming, then in its absence all we can do is question and challenge such stuff, and challenge we must vigorously.

That is exactly my reason to reply to Terence: I like to learn new things and often I read this forum to improve my skills. As me, I think there are many newbies: it is very helpful to pointing out that "goto" is "bad practice" and not for my stupid test ad dpb tried to allude, but because other distinguished coders have already proven. I am not up to the task to contribute to nothing even far similar to GOF work, but I offer my oompa loompa FOSS codes to discuss about best practice.

I am sure that soon we will obtain a good example (or from Gary's test, or from dpb experience) showing when/where use goto and this will improve my skills (because for now, I know only that goto is always overcome by other constructs), thus I am happy to debate with even harsh people, without mentioning to see your code examples.

My best regards.

Richard Maine

unread,
Oct 17, 2016, 1:04:32 PM10/17/16
to
I probably should just break down and killfile him, considering the
fairly consistent attitude displayed, but I do feel some obligation to
defend victims like the OP and assure them that we all aren't like that.

FortranFan <pare...@gmail.com> wrote:

> 1) The next time you post something, please make clear your thoughts and
> intent in the original postitself.

It was clear enough to some of us. I might even posit that it was most
of us rather than the few who got off onto debating things like speed.

> 2) When performance/speed is not important, please state so upfront.
> Fortranners are rather *anal* about this and as you can see,

I find it most unreasonable to ask someone to state those things that
they are not asking about. No, Fortranners are not anal about speed. You
overgeneralize. You can find some who are. And yep, if they are, they
are likely to speak up about it even in random contexts where it was not
mentioned at all. Quite a lot of us actually try to make judgements on
what is important in any particular situation rather than just jumping
on some pet peeve.

No, I'd say rather to clearly state what the question is before worrying
about what it is not. (And the OP did state it clearly enough in my
opinion.)

Hey, I've gotten enthusiastic about bicycling recently, and I know there
are several other people on his forum with a simillar interest. Maybe I
ought to ask all posters to explicitly state when they are not asking
about bicycling.

> 3) Please refrain from things such as "I am wondering if there is an
> easier way.", that's too vague on a Fortran forum.

I disagree. No further elaboration on my disagreement seems useful.

> And that's my opinion,

Well, that part I'll echo.

--
Richard Maine
email: last name at domain . net
dimnain: summer-triangle

dpb

unread,
Oct 17, 2016, 1:56:49 PM10/17/16
to
On 10/17/2016 11:07 AM, Stefano Zaghi wrote:
...

> I am sure that soon we will obtain a good example (or from Gary's
> test, or from dpb experience) showing when/where use goto and this will
> improve my skills (because for now, I know only that goto is always
> overcome by other constructs), thus I am happy to debate with even harsh
> people, without mentioning to see your code examples.

From me no further response seems warranted; the point was simply that
I can envision areas where it _might_ be possible to illustrate that a
particular compiler with a given universe of inputs could be shown to
favor one construct over another.

I didn't see that it was ever stated by Gary that he would use GOTO to
the exclusion of any other construct; only that he wouldn't reject using
it out of hand simply owing to the Standard having declared it
obsolescent. I don't see that that position is anything to get upset
over or try to convince him or anybody else that he's wrong if he could,
as noted, illustrate to his satisfaction an advantage in a particular
situation. I also don't believe it was anywhere in his posting a claim
that there would _necessarily_ be such a case uncovered.

That would, most likely, _NOT_ be with a modern optimizing compiler on a
workstation for general-purpose computing application where it's been
demonstrated already that all three competing constructs in isolation
generated identical code with at least one well-known compiler; ergo,
other than extraneous effects such as cache, OS preemption, etc., etc.,
etc., the performance would be identical on identical hardware with same
inputs and order of same.

That there are other universes of application seems to me obvious
although basically off topic for the initial poster's application.

As noted, imo Terrence is posting from his viewpoint of many years
experience much of which far predates F77 or even the extensions prior
to the Standard and on much more limited hardware than is typically used
for even minimal computing today. Hence, I'm not going to hound him for
not being on board necessarily with everything new and under the sun as
far as syntax.

So, carry on the good fight; I'm not (and have not) arguing the abstract
that "modern practice" is generally to be followed, only that as Gary if
I were to come across some place where I was particularly concerned over
every machine cycle I'd not be averse to using whatever construct new or
old that gave me the higher performance in that particular case despite
it perhaps being old-fashioned and out of favor.

FortranFan

unread,
Oct 17, 2016, 3:21:33 PM10/17/16
to
On Monday, October 17, 2016 at 1:04:32 PM UTC-4, Richard Maine wrote:

@Richard Maine,

> I probably should just break down and killfile him, considering the
> fairly consistent attitude displayed, but I do feel some obligation to
> defend victims like the OP and assure them that we all aren't like that.
>

You are absolutely wrong in suggesting I tried to make the OP a "victim" here: I was polite, frank, and honest in sharing my thoughts with him and I also tried to make clear to him he only consider my comments if he feels so inclined. It was not a "put down" of OP by any means and I think he'll understand what I meant.

>
> > 1) The next time you post something, please make clear your thoughts and
> > intent in the original postitself.
>
> It was clear enough to some of us. I might even posit that it was most
> of us rather than the few who got off onto debating things like speed.
> ..

Considering the first few comments, "Depends what you call easier", "It depends on what you mean by "easier."", "You have not provided many details," and your own first post in this thread to another poster trying to clarifying matters all point to the contrary, but hey "don't let the facts get in the way"


> .. No, Fortranners are not anal about speed. You
> overgeneralize.

Yes, you're absolutely right on this count, I wrote wrong.

@Pascal, my sincere apologies - I only meant to say some Fortran coders can be very concerned about speed and their suggestions can be based heavily on performance considerations which you will need to factor in relative to your needs when you are looking for "an easier way".

>
> No, I'd say rather to clearly state what the question is before worrying
> about what it is not. (And the OP did state it clearly enough in my
> opinion.)
>

Well, there are enough indications upthread that are contrary to your opinion.

> Hey, I've gotten enthusiastic about bicycling recently, and I know there
> are several other people on his forum with a simillar interest. Maybe I
> ought to ask all posters to explicitly state when they are not asking
> about bicycling.
>

I'm most discerning with my feedback to other readers and I stick to matters related to Fortran, those topics that advance Fortran and any that seem to have the potential to impede its progress - those who have similar interests and have an open and frank mind will understand.


> ..
>
> > And that's my opinion,
>
> Well, that part I'll echo.
>
> ..


I had meant to write, "that's *only* my opinion" for that's all it is - OP is, of course, totally free to chastise me or ignore my comments - my only hope is to have discussions and information exchanges that do not perpetuate any myths or biases regarding Fortran, should they prove to be as such.

I only joined in this thread when I noticed Terence's suggestions of using integer tables and like which had me quite curious. And later when he remarked, "prefer a computed GOTO over CASE anyway, since this is usually compiled as a faster selection" which, coming from someone with his background, is a *big deal*, if it can be understood better. That is not the case at present. Perhaps any subsequent divergence and any inadvertent propagation from the comment might have been prevented entirely with a differently formulated original post - I don't know, I'm just wondering.

Stefano Zaghi

unread,
Oct 17, 2016, 3:47:27 PM10/17/16
to
Dear dpb,

Il giorno lunedì 17 ottobre 2016 19:56:49 UTC+2, dpb ha scritto:
> From me no further response seems warranted;

This is sad to read, I hope to learn still a lot from you.

> the point was simply that
> I can envision areas where it _might_ be possible to illustrate that a
> particular compiler with a given universe of inputs could be shown to
> favor one construct over another.

Wonderful, I ask just for one simple example where goto is better than others, not for a whole universe, but I you are so kind to give me a universe it is more than welcome.

> I didn't see that it was ever stated by Gary that he would use GOTO to
> the exclusion of any other construct; only that he wouldn't reject using
> it out of hand simply owing to the Standard having declared it
> obsolescent.

Again you consider only what you want omitting other parts, it is not the obsolescence the reason to avoid goto rather there are good reasons why it is now obsolescent. You so precise and carefull when you want, but with me become so superficial...

> I don't see that that position is anything to get upset
> over or try to convince him or anybody else that he's wrong if he could,
> as noted, illustrate to his satisfaction an advantage in a particular
> situation.

Probably, I'll be the most happy here if someone shows me with proofs that goto provides any sort of advantages, this what I asked for "illustrate to me the good of goto".

> I also don't believe it was anywhere in his posting a claim
> that there would _necessarily_ be such a case uncovered.

"Necessary"... nothing is necessary. I stated that without a reproducibile test his conclusions are meaningless.

> That would, most likely, _NOT_ be with a modern optimizing compiler on a
> workstation for general-purpose computing application where it's been
> demonstrated already that all three competing constructs in isolation
> generated identical code with at least one well-known compiler; ergo,
> other than extraneous effects such as cache, OS preemption, etc., etc.,
> etc., the performance would be identical on identical hardware with same
> inputs and order of same.
>
> That there are other universes of application seems to me obvious
> although basically off topic for the initial poster's application.

Let us go OT a quite: give me just one example, I do not need a whole universe.

> As noted, imo Terrence is posting from his viewpoint of many years
> experience much of which far predates F77 or even the extensions prior
> to the Standard and on much more limited hardware than is typically used
> for even minimal computing today.

I agree, nevertheless his sentence is worng, goto is NOT generally compiled into faster code, do you agree?

> Hence, I'm not going to hound him for
> not being on board necessarily with everything new and under the sun as
> far as syntax.

Feel free to remain at age you like. For the sake of clearness and for newbies like me, I simple states that goto is obsolescent and to be avoid for many good resons aforementioned.

> So, carry on the good fight; I'm not (and have not) arguing the abstract
> that "modern practice" is generally to be followed, only that as Gary if
> I were to come across some place where I was particularly concerned over
> every machine cycle I'd not be averse to using whatever construct new or
> old that gave me the higher performance in that particular case despite
> it perhaps being old-fashioned and out of favor.

Please, show me where "the higher performance" is obtained by means of goto.

I have replied with kindness, I still waiting a weak apolozing for your harsh allusion to my manhood.

My best regards.

Stefano Zaghi

unread,
Oct 17, 2016, 4:02:13 PM10/17/16
to
Dear Richard,

Il giorno lunedì 17 ottobre 2016 21:21:33 UTC+2, FortranFan ha scritto:
> On Monday, October 17, 2016 at 1:04:32 PM UTC-4, Richard Maine wrote:
>
> @Richard Maine,
>
> > I probably should just break down and killfile him, considering the
> > fairly consistent attitude displayed, but I do feel some obligation to
> > defend victims like the OP and assure them that we all aren't like that.

Your reply to FortranFan post alludes to the fact that FortranFan was harsh with Pascal while you are in the "good club" of kind Fortraners. Your post demonstrates the contary, you are harsh with FortranFan and almost indiferrent with Pascal...

> You are absolutely wrong in suggesting I tried to make the OP a "victim" here: I was polite, frank, and honest in sharing my thoughts with him and I also tried to make clear to him he only consider my comments if he feels so inclined. It was not a "put down" of OP by any means and I think he'll understand what I meant.

I agree, I remember many Richard's posts devoted to educating OPs on which is the "best practice" to create a post... the one of FortranFan is on the same line and as usefull as the one of Richard.

> > > 1) The next time you post something, please make clear your thoughts and
> > > intent in the original postitself.
> >
> > It was clear enough to some of us. I might even posit that it was most
> > of us rather than the few who got off onto debating things like speed.
> > ..
>
> Considering the first few comments, "Depends what you call easier", "It depends on what you mean by "easier."", "You have not provided many details," and your own first post in this thread to another poster trying to clarifying matters all point to the contrary, but hey "don't let the facts get in the way"

I agree.

> > > And that's my opinion,
> >
> > Well, that part I'll echo.
> >
> > ..
>
>
> I had meant to write, "that's *only* my opinion" for that's all it is - OP is, of course, totally free to chastise me or ignore my comments - my only hope is to have discussions and information exchanges that do not perpetuate any myths or biases regarding Fortran, should they prove to be as such.

I cannot speak for Pascal, but I like FortranFan suggestions, instead of referring to Pascal I like to consider them referred to my bad addictions and I'll try to follow them when I'll post a new call for your help.

My best regards.

Richard Maine

unread,
Oct 17, 2016, 4:19:26 PM10/17/16
to
Dpb and I are often pretty much on the same wavelength, and this appears
to be one of many such cases, so I'll take the liberty of answering,
which of course doesn't mean he can't answer as well.

Stefano Zaghi <stefan...@gmail.com> wrote:

> Let us go OT a quite: give me just one example, I do not need a whole
> universe.

You seem to miss some important small words. Small words are often quite
important, as they are often ones that were introduced into the language
very early. In this case, there was an "if" back there somewhere, either
explicit or implied.

With that "if", Dpb just acknowledged the possibility that there might
be such a case. He didn't say he had one. Nor do I, as much as anything
because I don't feel any particular obligation to go searching for one.
I am actually capable of realizing that things other than ones I have
seen are possible. That doesn't mean I necessarily accept that they must
exist - just that I acknowledge the possibility that they might. No, I
don't feel obligated to try to investigate the entire universe of
possibilities to see if I can find one just in order to satisfy someone
else's question. If you can't accept the possibility without seeing an
example, I guess I'll just have to let that be.

> I I still waiting a weak apolozing for your harsh allusion to my manhood.

Another small but important word you missed was "not". That's often an
incredibly important one. Dpb said that people were *NOT* questioning
your manhood. Perhaps you might also be missing the idiomatic use of
that phrase. The idiomatic implication is that the questions being
raised were not things to get overly excited about and that the
discussion need no be so vehement as it appeared to be getting. I'd
quite agree on that and it doesn't seem like something that merits
apology for.

dpb

unread,
Oct 17, 2016, 4:29:55 PM10/17/16
to
On 10/17/2016 2:47 PM, Stefano Zaghi wrote:
...

...

> "Necessary"... nothing is necessary. I stated that without a
> reproducibile test his conclusions are meaningless.

Well, you're at liberty to ignore them; I'm willing to accept his word
at face value as being so for the case he tested...

...

> Let us go OT a quite: give me just one example, I do not need a whole universe.

I thought I had--a realtime system with limited hardware and compiler(s)...

...

> I agree, nevertheless his sentence is worng, goto is NOT generally
> compiled into faster code, do you agree?

For a specific _modern_ optimizing compiler I've just gone on at length
that the three constructs were shown to all generate _identical_ code.

That doesn't prove the universe of current compilers all being that
capable and particularly not if one also includes previous generations
of compilers on older hardware that may not have the same optimization
levels, or of course, that don't support CASE at all, perhaps.

It's pretty much a moot point regarding current workstations and the
like I'd expect; as I noted the much older compiler I do have but it's
not installed on a machine that is used other than as being archived
"just in case" were to ever be asked to update a now 30-40 yr old
application that is, amazingly enough, still in use at some utility
power plants. It's highly unlikely that'll ever happen again, but I did
bring the system out of mothballs to ensure it would handle the 2000
rollover ok and once again a couple of years later to add a new module
for the scrubbers added to one of the units so it's not totally out of
the question. But, this question isn't of burning-enough interest for
me to go to the trouble to see how the options compare on it, but that'd
be my first guess at one that just _might_ show a consistent bias. Then
again, it's possible it also just generates a jump table, too, I don't
know for sure; never tested it.

Perhaps the tone wasn't intended as harsh as I read it and is simply a
case of language--certainly your English is far better than my
facilities in whatever your native tongue would be... :) If that's the
case and the criticism really wasn't intended then you've got the
apology...reading the words sounded pretty "fired up" to me...

Stefano Zaghi

unread,
Oct 17, 2016, 4:41:40 PM10/17/16
to
Dear Richard,

Il giorno lunedì 17 ottobre 2016 22:19:26 UTC+2, Richard Maine ha scritto:
> Dpb and I are often pretty much on the same wavelength, and this appears
> to be one of many such cases, so I'll take the liberty of answering,
> which of course doesn't mean he can't answer as well.

Reply on the behalf of whom you like, your posts are always welcome.

> You seem to miss some important small words. Small words are often quite
> important, as they are often ones that were introduced into the language
> very early. In this case, there was an "if" back there somewhere, either
> explicit or implied.

You are wrong, I see the "if", this is indeed crucial.

> With that "if", Dpb just acknowledged the possibility that there might
> be such a case. He didn't say he had one.

Perfectly clear, thus it should be allowed to me to say "I never see a case where goto is better than others constructs". When you will be so kind to prove me the contrary I will be very happy.

> Nor do I, as much as anything
> because I don't feel any particular obligation to go searching for one.

No one is here obligated to do nothing, we are simply talking. I argumented my point with reproducible test (with books) with what the current Standard states, you argumented with "if". Let redears make your own opinions.

> I am actually capable of realizing that things other than ones I have
> seen are possible.

Are we still talking about goto or phylosofy? I am atheist FYI.

> No, I
> don't feel obligated to try to investigate the entire universe of
> possibilities to see if I can find one just in order to satisfy someone
> else's question.

You are not obligated to do nothing. I asked for an insight, simply ignore me, I know you are in the "club of not so kind" Fotraners.

> If you can't accept the possibility without seeing an
> example, I guess I'll just have to let that be.

Yes, I am used to not accept all sentences just because someone said them, I am used to search for proofs.

> Another small but important word you missed was "not". That's often an
> incredibly important one. Dpb said that people were *NOT* questioning> your > > manhood. Perhaps you might also be missing the idiomatic use of
> that phrase. The idiomatic implication is that the questions being
> raised were not things to get overly excited about and that the
> discussion need no be so vehement as it appeared to be getting. I'd
> quite agree on that and it doesn't seem like something that merits
> apology for.

Prheaps my bad English mislead me, if so my sincere apologize, whereas that sentence still sound a free-harsh served sentence.

My best regards.

herrman...@gmail.com

unread,
Oct 17, 2016, 4:51:13 PM10/17/16
to
On Monday, October 17, 2016 at 10:04:32 AM UTC-7, Richard Maine wrote:
> I probably should just break down and killfile him, considering the
> fairly consistent attitude displayed, but I do feel some obligation to
> defend victims like the OP and assure them that we all aren't like that.

> FortranFan <parek...@gmail.com> wrote:

> > 1) The next time you post something, please make clear your thoughts and
> > intent in the original postitself.

> It was clear enough to some of us. I might even posit that it was most
> of us rather than the few who got off onto debating things like speed.

I suspect it is a rare post that gives 100% of the information needed to
answer, and no more. But even when it does, the discussion might drift
to related, and sometimes not so related topics.

Discussions here are for all to learn from. Most of us post here so we
can learn more. Sometimes the original question reminds someone of
another question, related enough not to need a new thread, but also maybe
not answering the original question. It might even drift to the question that
the OP needs answered next, but hadn't though about yet!

I have been wondering about optimizations of computed GOTO vs.
SELECT/CASE for a long time, though as noted, often it doesn't matter.

> > 2) When performance/speed is not important, please state so upfront.
> > Fortranners are rather *anal* about this and as you can see,

> I find it most unreasonable to ask someone to state those things that
> they are not asking about. No, Fortranners are not anal about speed. You
> overgeneralize.

(snip)

There is a famous quote from D. Knuth:

"The real problem is that programmers have spent far
too much time worrying about efficiency in the wrong
places and at the wrong times; premature optimization
is the root of all evil (or at least most of it) in programming."

(For more, see: https://en.wikiquote.org/wiki/Donald_Knuth )

As I noted in another discussion, it is now just over 60 years
since the beginning of Fortran programming. Fortran programmers
may not worry more about speed, but they have been doing it longer
than those for most other languages today.

And to continue thread drift, hopefully interesting to readers here,
there are stories about the first Fortran compiler. At the time, it
was usual to do assembly programming, and they realized that they
were competing against code generated by those programmers.

Optimization was, then, considered very important in that first
compiler. If programs weren't fast enough, people wouldn't use
their new language and compiler. (Computers were a lot slower,
so that speed was more important than today.)

Oh, and by the way, computed GOTO traces back to that first
compiler 60 years ago. SEELCT/CASE is much more recent.

Stefano Zaghi

unread,
Oct 17, 2016, 4:57:58 PM10/17/16
to
Dear dpb,

Il giorno lunedì 17 ottobre 2016 22:29:55 UTC+2, dpb ha scritto:
> Well, you're at liberty to ignore them; I'm willing to accept his word
> at face value as being so for the case he tested...

This should be clear and I hope it will be clear also in the future: I am free (you are free) to consider or ignore any of your (mine) sentences. I just like to debate with whom think differently from me to learn new things. I argumented my point, feel free to ignore my arguments. I'll not ignore yours.

> I thought I had--a realtime system with limited hardware and compiler(s)...

I got it. I search for a concrete example: a full program showing the supposed better goto peformance on this limited hardawre. If you are referring to a very old architecture where select case or if elseif are not available (up to F77), well this is really OT, we are comparing goto with select case.

> For a specific _modern_ optimizing compiler I've just gone on at length
> that the three constructs were shown to all generate _identical_ code.

I got, I agree.

> That doesn't prove the universe of current compilers all being that
> capable and particularly not if one also includes previous generations
> of compilers on older hardware that may not have the same optimization
> levels, or of course, that don't support CASE at all, perhaps.

If they do not support select case we are only wasting time, we are comparing goto with select case.

> It's pretty much a moot point regarding current workstations and the
> like I'd expect; as I noted the much older compiler I do have but it's
> not installed on a machine that is used other than as being archived
> "just in case" were to ever be asked to update a now 30-40 yr old
> application that is, amazingly enough, still in use at some utility
> power plants. It's highly unlikely that'll ever happen again, but I did
> bring the system out of mothballs to ensure it would handle the 2000
> rollover ok and once again a couple of years later to add a new module
> for the scrubbers added to one of the units so it's not totally out of
> the question. But, this question isn't of burning-enough interest for
> me to go to the trouble to see how the options compare on it, but that'd
> be my first guess at one that just _might_ show a consistent bias. Then
> again, it's possible it also just generates a jump table, too, I don't
> know for sure; never tested it.

Interesting, thank you for sharing the story.

> Perhaps the tone wasn't intended as harsh as I read it and is simply a
> case of language--certainly your English is far better than my
> facilities in whatever your native tongue would be... :)

I am Italian. Your Italian is surely better than my English even if your Italian is limited to "spaghetti" (code).

> If that's the
> case and the criticism really wasn't intended then you've got the
> apology...reading the words sounded pretty "fired up" to me...

Thank you very much, it is very appreciated.

My best regards.

Stefano Zaghi

unread,
Oct 17, 2016, 5:06:37 PM10/17/16
to
Dear Glen,

Il giorno lunedì 17 ottobre 2016 22:51:13 UTC+2, herrman...@gmail.com ha scritto:
> As I noted in another discussion, it is now just over 60 years
> since the beginning of Fortran programming. Fortran programmers
> may not worry more about speed, but they have been doing it longer
> than those for most other languages today.
>
> And to continue thread drift, hopefully interesting to readers here,
> there are stories about the first Fortran compiler. At the time, it
> was usual to do assembly programming, and they realized that they
> were competing against code generated by those programmers.

Such stories are really interesting for me that I do not known in person a "youngester" who experienced those days. Can you point me to any resources (book, forum, webpages...) concerning such topics? It would be wonderful if in the post you mentioned about the 60' anniversary you can add some of the most interesting stories.

My best regards.

Pascal

unread,
Oct 17, 2016, 5:25:47 PM10/17/16
to
On 17/10/2016 20:21, FortranFan wrote:
> On Monday, October 17, 2016 at 1:04:32 PM UTC-4, Richard Maine
> wrote:
>
>> .. No, Fortranners are not anal about speed. You overgeneralize.
>
> Yes, you're absolutely right on this count, I wrote wrong.
>
> @Pascal, my sincere apologies - I only meant to say some Fortran
> coders can be very concerned about speed and their suggestions can be
> based heavily on performance considerations which you will need to
> factor in relative to your needs when you are looking for "an easier
> way".
>

No worries.

I am as well when I need to. I just did not mention performance because
I did not need any.



Pascal

herrman...@gmail.com

unread,
Oct 17, 2016, 5:45:29 PM10/17/16
to
On Monday, October 17, 2016 at 1:19:26 PM UTC-7, Richard Maine wrote:

(snip)

> > I I still waiting a weak apolozing for your harsh allusion to my manhood.

> Another small but important word you missed was "not". That's often an
> incredibly important one. Dpb said that people were *NOT* questioning
> your manhood. Perhaps you might also be missing the idiomatic use of
> that phrase. The idiomatic implication is that the questions being
> raised were not things to get overly excited about and that the
> discussion need no be so vehement as it appeared to be getting. I'd
> quite agree on that and it doesn't seem like something that merits
> apology for.

That used to be the meaning. Now, for some reason that I don't
understand, it has to do with the size of someone's hands.

Gordon Sande

unread,
Oct 17, 2016, 7:17:17 PM10/17/16
to
On 2016-10-17 20:41:38 +0000, Stefano Zaghi said:

> Dear Richard,
>
> Il giorno lunedě 17 ottobre 2016 22:19:26 UTC+2, Richard Maine ha scritto:
>> Dpb and I are often pretty much on the same wavelength, and this appears
>> to be one of many such cases, so I'll take the liberty of answering,
>> which of course doesn't mean he can't answer as well.
>
> Reply on the behalf of whom you like, your posts are always welcome.
>
>> You seem to miss some important small words. Small words are often quite
>> important, as they are often ones that were introduced into the language
>> very early. In this case, there was an "if" back there somewhere, either
>> explicit or implied.
>
> You are wrong, I see the "if", this is indeed crucial.
>
>> With that "if", Dpb just acknowledged the possibility that there might
>> be such a case. He didn't say he had one.
> Perfectly clear, thus it should be allowed to me to say "I never see a
> case where goto is better than others constructs". When you will be so
> kind to prove me the contrary I will be very happy.

If you are implementing a state machine, often well deined elsewhare,
the use of GOTOs
is most natural. In these cases it may well be that Fortran is only the
implementation
language used by software which "compiles" the state machine into some
intermediate
code, i.e. Fortran. It may well be that the use of GOTO simpliies the
"compilation"
problem as either CASE or an IF nest would be much more awkward ot produce.

Gary Scott

unread,
Oct 17, 2016, 8:18:59 PM10/17/16
to
I'm sampling CPU clock ticks per the MKL and win os OS procedures for
doing so. I realize that there are issues with this timing method, but
for this purpose, it suitable. I compare against the real time value
returned by date_and_time to identify any sampling glitches. It is
typically very obvious when this occurs (paging, task switch, etc.).

Gary Scott

unread,
Oct 17, 2016, 8:26:44 PM10/17/16
to
On 10/17/2016 9:41 AM, Stefano Zaghi wrote:
> Dear dpb,
>
> Il giorno lunedì 17 ottobre 2016 16:00:17 UTC+2, dpb ha scritto:
>> You're fixating on a single benchmark result and ignoring the (even
>> emphasized) suppositional _IF_ postulates of the response. It was
>> indicated "YES", under a specific set of circumstances which would
>> likely (I'm inferring and/or amplifying here) include a limited hardware
>> environment, possibly even a realtime one with time constraints in a
>> very controlled situation where inputs are known a priori to be within
>> some specific set of conditions.
>
> It is funny that you reply for Gary, maybe you can reply also to my previous post for you.
>
> Anyhow, I am not "fixated" on nothing. You are again say a "false myth concerning me": I do not thrust even in my own test, why you can say "I am fixating on the result of 1 test"? Really a silly sentence. I simply report what I learn on many good book and I learn from some good coders: goto is obsolescent for many good reasons.
>
> In my last post to Gary I simply assumed that his test indicates a 5% speedup for goto and asked if in that scenario he hesitate or not to use goto, this is just a confirm for me-donkey-student. What it the matter with you? Your noise about real-time-constraints is very OT. We start comparing goto with select case...
>

In a subsequent post I identified where there I prototyped a scenario in
which there was zero difference between the 3 cases +/- 3ns average for
10000 samples.

I prototyped scenarios (i.e. test order change) in which either goto or
select case was faster by a very tiny amount. On average however, there
were more cases where goto exhibited worse performance, but I did not
identify whether there was some additional OS task switching or
something else that might have altered the cpu clock tick sampling
rate/process.

dpb

unread,
Oct 17, 2016, 10:45:59 PM10/17/16
to
On 10/17/2016 3:57 PM, Stefano Zaghi wrote:
...

> If they do not support select case we are only wasting time, we are
> comparing goto with select case.
...

Well, the particular compiler was/is an extended F77 with the CASE
construct available; what I don't know is whether it generated the same
jump-table code as the computed GOTO or not...I can see it being quite
possible it wasn't yet optimized as well but then again, it may have
been--I had no reason to ever test it. And, of course, the vendor
dropped support for Fortran entirely not terribly long after...

But, there were actually three cases -- as James Van B. showed, the
IF...END block also generated the same jump table in IVF.

Stefano Zaghi

unread,
Oct 18, 2016, 12:19:03 AM10/18/16
to
Dear Gordon,
Il giorno martedì 18 ottobre 2016 01:17:17 UTC+2, Gordon Sande ha scritto:
> If you are implementing a state machine, often well deined elsewhare,
> the use of GOTOs
> is most natural.

Thank you very much, your example is very good. Goto takes place nowadays in a very small field, as you noted, like state machine or exceptions handling (cleaner). However, we could discuss a lot if it is "more natural" to have a spaghetti code jumping potentially everywhere rather than some nested clearly named "do/if/select" constructs. For example, to my taste I prefer to try to implement a state pattern rather pollute my code with goto (and say goodbye to multi-threading).

> In these cases it may well be that Fortran is only the
> implementation
> language used by software which "compiles" the state machine into some
> intermediate
> code, i.e. Fortran. It may well be that the use of GOTO simpliies the
> "compilation"
> problem as either CASE or an IF nest would be much more awkward ot produce.

Sure, I agree. Anyhow, I am not an assembler coder or a compiler developer. I love Fortran because it is a very high level language allowing my to forget about low level details and to focus of what much counts for me, the physical-math. It is surely true that other languages compile into an intermediate Fortran goto based code, but this is not a good reason to develop new Fortran codes by means of goto.

To elaborate a bit more: I have great respect for the Standard committee, I think that they are superheroes. If they declared goto obsolescent, this means that there are more effective/reliable approaches to implement what could be implemented by means of goto. I know that many consider "more natural" an exceptions handling by means of goto, I do not for good reasons aforementioned.

Anyhow, I never see a concrete example of goto-based exceptions handling (my books start from F95), it could be very helpful to improve my Fortran knowledge to study such a program: can you point me to some good resources on the topic?

Thank you again.

My best regards.

Stefano Zaghi

unread,
Oct 18, 2016, 12:28:40 AM10/18/16
to
Dear Gary.

Il giorno martedì 18 ottobre 2016 02:26:44 UTC+2, Gary Scott ha scritto:
> In a subsequent post I identified where there I prototyped a scenario in
> which there was zero difference between the 3 cases +/- 3ns average for
> 10000 samples.

Thank you for your effort, I like to debate with you. Anyhow, as I said, you spend more lines to descibes what "you think to have identified" than to provide a simple reproducible test. I can assure you that I thrust you in principle, but until I cannot reproduce your test, speaking about +- 3ns is meaningless for me. Anyhow, I have gone further and asked to you if an ipothetical scenario where goto is a little bit faster than select case you will use it or not. My position should be known: for such a low speedup goto offers much more cons than pros thus I will avoided it. Your position is unclear for me.

> I prototyped scenarios (i.e. test order change) in which either goto or
> select case was faster by a very tiny amount. On average however, there
> were more cases where goto exhibited worse performance, but I did not
> identify whether there was some additional OS task switching or
> something else that might have altered the cpu clock tick sampling
> rate/process.

Let us to try to investigate this strange behaviour it could be a very educating exercise, but I need a reproducible test.

My best regards.

Stefano Zaghi

unread,
Oct 18, 2016, 12:45:40 AM10/18/16
to
Dear dpb,

Il giorno martedì 18 ottobre 2016 04:45:59 UTC+2, dpb ha scritto:
> Well, the particular compiler was/is an extended F77 with the CASE
> construct available; what I don't know is whether it generated the same
> jump-table code as the computed GOTO or not...I can see it being quite
> possible it wasn't yet optimized as well but then again, it may have
> been--I had no reason to ever test it. And, of course, the vendor
> dropped support for Fortran entirely not terribly long after...

As always I appreciate to learn by you, but, franckly speaking, I really do not understand your way to teach in this case.

It should be clear by my very early post of this discussion that taking into account very old architecture/compiler is almost pointless (for me) with respect my replay to Terence and to all the subsequent posts.

Terence prodived a very sharp sentence "goto is generally compiled into a faster code", without any reference to old-good days. We are leaving into 2016, this sentence is simlply FALSE.

Then your defence of Terence's point is really a "pedantic" puntualization (OT when comparing goto with select case) about "there is universe of cases where goto is better": this universe seems to be related to the pre 90 era.

You seem to think that I am so stupid to not understand that in those days goto was better: you could simply say "hey Stefano, remember that for someone the clock is fixed at F77 and goto is your way", I will reply "your rigth, I am sorry to forget youngesters", whereas not, I obtained "there is a universe of cases where goto is wonderful" (alluding to my fixing on only one stupid test) thus coming my request for a good example. My English is surely bad, but sometimes trying to come-down from pedestal could be very helpfull.

That was said with sincerity and friendly-soul.

> But, there were actually three cases -- as James Van B. showed, the
> IF...END block also generated the same jump table in IVF.

Yes, James' post confirm my conclusions, the sentence of Terence is currently false.

My best regards.

Ron Shepard

unread,
Oct 18, 2016, 1:33:25 AM10/18/16
to
On 10/16/16 10:11 PM, Ian Harvey wrote:
> [...] and the same block of code can be addressed by multiple labels.

You might think there would be situations where this might be an
advantage over SELECT CASE, but in fact you can do the same thing with
that construct too.

select case (ikey)
case (1,2); call s1and2()
case (3,4); call s3and4()
end select

But there is one situation that seems to be better with computed GOTO
than SELECT CASE. Something like this:

goto (1,2,3,4), ikey
1 call s1()
2 call s2()
3 call s3()
4 call s4()
...

In this case, you *WANT* the execution flow to fall through to the other
cases, and the computed goto determines where to start the process. With
SELECT CASE, you must do this by repeating the statements for the
various cases separately, which is somewhat inelegant.

$.02 -Ron Shepard

Stefano Zaghi

unread,
Oct 18, 2016, 4:39:56 AM10/18/16
to
Dear Ron,

Il giorno martedì 18 ottobre 2016 07:33:25 UTC+2, Ron Shepard ha scritto:
> You might think there would be situations where this might be an
> advantage over SELECT CASE, but in fact you can do the same thing with
> that construct too.
>
> select case (ikey)
> case (1,2); call s1and2()
> case (3,4); call s3and4()
> end select
>
> But there is one situation that seems to be better with computed GOTO
> than SELECT CASE. Something like this:
>
> goto (1,2,3,4), ikey
> 1 call s1()
> 2 call s2()
> 3 call s3()
> 4 call s4()
> ...
>
> In this case, you *WANT* the execution flow to fall through to the other
> cases, and the computed goto determines where to start the process. With
> SELECT CASE, you must do this by repeating the statements for the
> various cases separately, which is somewhat inelegant.
>
> $.02 -Ron Shepard

Thank you very much for this very nice example. However, the same "flow" can be achieved with a simple "if".

Consider the following program

---code
program flushed_flow
use iso_fortran_env
implicit none
integer(int32), parameter :: tests_number = 2
integer(int32) :: keyword
real(real64) :: random
integer(int32) :: i

do i=1, tests_number
call random_number(random)
keyword = nint(random*4, int32)

print '(A)', 'goto flow'
goto (1, 2, 3, 4), keyword
1 call worker1(key=keyword)
2 call worker2(key=keyword)
3 call worker3(key=keyword)
4 call worker4(key=keyword)

print '(A)', 'if flow'
if (keyword<2) call worker1(key=keyword)
if (keyword<3) call worker2(key=keyword)
if (keyword<4) call worker3(key=keyword)
if (keyword<5) call worker4(key=keyword)
end do

contains
subroutine worker1(key)
integer(int32), intent(in) :: key

print '(A,I3)', 'I am worker 1 and keyword is ', key
endsubroutine worker1

subroutine worker2(key)
integer(int32), intent(in) :: key

print '(A,I3)', 'I am worker 2 and keyword is ', key
endsubroutine worker2

subroutine worker3(key)
integer(int32), intent(in) :: key

print '(A,I3)', 'I am worker 3 and keyword is ', key
endsubroutine worker3

subroutine worker4(key)
integer(int32), intent(in) :: key

print '(A,I3)', 'I am worker 4 and keyword is ', key
endsubroutine worker4
end program flushed_flow
---end code


The "if" flow produces the same flow-bias as the goto one, i.e.

---output
stefano@zaghi(10:32 AM Tue Oct 18)
~ 27 files, 6.1Mb
→ gfortran flushed_flow.f90

stefano@zaghi(10:33 AM Tue Oct 18)
~ 27 files, 6.1Mb
→ a.out
goto flow
I am worker 4 and keyword is 4
if flow
I am worker 4 and keyword is 4
goto flow
I am worker 2 and keyword is 2
I am worker 3 and keyword is 2
I am worker 4 and keyword is 2
if flow
I am worker 2 and keyword is 2
I am worker 3 and keyword is 2
I am worker 4 and keyword is 2
---end output

Now we can discuss which is preferable over other: I prefer the "if" for the aforementioned reasons, why you prefer the "goto" one?

My best regards.

dpb

unread,
Oct 18, 2016, 8:56:32 AM10/18/16
to
On 10/17/2016 11:45 PM, Stefano Zaghi wrote:
...

> Yes, James' post confirm my conclusions, the sentence of Terence is currently false.

Well, it confirmed it for a particular compiler, anyway...Terence's
favorite I still don't know about. :)

FortranFan

unread,
Oct 18, 2016, 9:14:24 AM10/18/16
to
On Monday, October 17, 2016 at 5:25:47 PM UTC-4, Pascal wrote:

> On 17/10/2016 20:21, FortranFan wrote:
> ..
> > @Pascal, my sincere apologies - I only meant to say some Fortran
> > coders can be very concerned about speed and their suggestions can be
> > based heavily on performance considerations which you will need to
> > factor in relative to your needs when you are looking for "an easier
> > way".
> >
>
> No worries.
>
> ..


@Pascal,

Thanks much for your understanding.

By the way, your recent follow-up comment was, "To be honest, python would be more suited for this kind of stuff".

So will it be possible for you to put together a minimal working example of your use case (i.e., what you are trying to do with keyword processing as you stated in the original post) in Fortran and the same case in what you think is the "more suited" manner in Python and post both of them here? I think it will be most useful for some of us who are highly curious about language facilities and programming patterns and what all make coders think a particular programming paradigm is more suited for their tasks versus others.

So I'll appreciate greatly if you are able to share your thoughts with actual code on how your Python code compares with your Fortran one that will have the SELECT CASE construct.

By the way, since Python does not include any 'switch/select case' functionality, I assume your point about Python being 'more suited' was with the use of some built-in facility, perhaps a dictionary (map) to achieve your task? If that's case, you would know that behind the scenes, Python will be effectively making use of a struct/class (a derived type and type-bound procedures in Fortran parlance) which is what several readers informed you as another option. That approach may not be 'easier' to code the first time, depending on how you define 'easier', but if there are frequent needs in other program modules and applications, then the initial effort of building such scaffolding can quickly be paid off.

But now that you have brought up Python, the main difference is Python (and other languages) offer such "goodies" for coders i.e., *built-in* options for 'containers' which allow a certain section (probably vast) of coders become 'satisfied' consumers of the language, kinda like how you're thinking Python is more suited for the stuff you have in mind here. Along such lines, I've tried to make a case for more 'intrinsic' derived types with type-bound procedures in Fortran (possibly even with Fortran ABSTRACT attribute) that offer 'container' classes via more 'intrinsic' modules, see this:

https://groups.google.com/forum/#!searchin/comp.lang.fortran/Fortran$20generic$20types%7Csort:relevance/comp.lang.fortran/R_zBfQKmcHE/5a_KthCMBgAJ


Anyways, if you're interested in a simple-minded 'dictionary' type of example in Fortran for the case you present in the original post, please comment and I can post one here; Stefano Zaghi and others will most likely have far more advanced 'classes' on GitHub, etc. that you can employ for your needs too.

I'll be most eager to see if you are able to follow-up as I request above with Python and Fortran minimal working examples of your use case and your analysis (however brief) on the 'easier way' regarding these two approaches.

Most Sincerely,

Stefano Zaghi

unread,
Oct 18, 2016, 10:16:20 AM10/18/16
to
Dear FortranFan,

Il giorno martedì 18 ottobre 2016 15:14:24 UTC+2, FortranFan ha scritto:
> So will it be possible for you to put together a minimal working example of your use case (i.e., what you are trying to do with keyword processing as you stated in the original post) in Fortran and the same case in what you think is the "more suited" manner in Python and post both of them here? I think it will be most useful for some of us who are highly curious about language facilities and programming patterns and what all make coders think a particular programming paradigm is more suited for their tasks versus others.
>
> So I'll appreciate greatly if you are able to share your thoughts with actual code on how your Python code compares with your Fortran one that will have the SELECT CASE construct.
>
> By the way, since Python does not include any 'switch/select case' functionality, I assume your point about Python being 'more suited' was with the use of some built-in facility, perhaps a dictionary (map) to achieve your task? If that's case, you would know that behind the scenes, Python will be effectively making use of a struct/class (a derived type and type-bound procedures in Fortran parlance) which is what several readers informed you as another option. That approach may not be 'easier' to code the first time, depending on how you define 'easier', but if there are frequent needs in other program modules and applications, then the initial effort of building such scaffolding can quickly be paid off.

I cannot speak for Pascal, thus Pascal feel free to castigate me if I am wrong.

I think that Pascal is a "wiseman" for select Python for such a task. However, my reasons to flavor Python are not strictly related to its great support for generic containers (that we mimic, in very limited fashion, in Fortran) rather Python is really "introspective". I cannot reproduce exactly the Pascal's scenario, but on the base of what we know, please consider the following complete Python program

---code
!/usr/bin/env python

from __future__ import print_function
import argparse


def worker1(key=None):
"""Worker 1"""
print('I am worker 1 and keyword is ', str(key))
return


def worker2(key=None):
"""Worker 2"""
print('I am worker 2 and keyword is ', str(key))
return


def worker3(key=None):
"""Worker 1"""
print('I am worker 3 and keyword is ', str(key))
return


def parse_file(filename=None):
"""Parse keywords file"""
keywords = []
with open(filename) as keys:
keywords = keys.readlines()
keywords = [key.strip() for key in keywords]
return keywords

if __name__ == '__main__':
__cliparser__ = argparse.ArgumentParser()
__cliparser__.add_argument('-i', '--input',
required=True,
action='store',
default=None,
help='Input file name of keywords to be parsed')
__cliargs__ = __cliparser__.parse_args()
__keywords__ = parse_file(filename=__cliargs__.input)
print('Keywords processed:')
print(__keywords__)
print('Workers calls:')
__workers__ = globals().copy()
__workers__.update(locals())
for __key__ in __keywords__:
__worker__ = __workers__.get(__key__)
if __worker__ is None:
raise NotImplementedError("Worker %s not implemented" % __key__)
__worker__(key=__key__)
---end code

Aside the fact that I am a worse Pythoner, look at some crucial statements, namely:


__workers__ = globals().copy()
__workers__.update(locals())
for __key__ in __keywords__:
__worker__ = __workers__.get(__key__)


This is really "introspection": I am obtaining a function by a string.

To my knowledge this is not possible in pure Fortran (that is not an interpreted language). Running the above code you obtain also fancy alert when a particular keyword is not yet support, i.e.

---output
→ ./keys_parse.py -i keywords.dat
Keywords processed:
['worker1', 'worker2', 'worker3', 'worker4']
Workers calls:
I am worker 1 and keyword is worker1
I am worker 2 and keyword is worker2
I am worker 3 and keyword is worker3
Traceback (most recent call last):
File "./keys_parse.py", line 50, in <module>
raise NotImplementedError("Worker %s not implemented" % __key__)
NotImplementedError: Worker worker4 not implemented
---end output

Python has a very nice exceptions handling too.

As you argued I have exploited (generic) list built-in (with also list-comprehension for strip out newlines characters).


> But now that you have brought up Python, the main difference is Python (and other languages) offer such "goodies" for coders i.e., *built-in* options for 'containers' which allow a certain section (probably vast) of coders become 'satisfied' consumers of the language, kinda like how you're thinking Python is more suited for the stuff you have in mind here. Along such lines, I've tried to make a case for more 'intrinsic' derived types with type-bound procedures in Fortran (possibly even with Fortran ABSTRACT attribute) that offer 'container' classes via more 'intrinsic' modules, see this:
>
> https://groups.google.com/forum/#!searchin/comp.lang.fortran/Fortran$20generic$20types%7Csort:relevance/comp.lang.fortran/R_zBfQKmcHE/5a_KthCMBgAJ
>
>
> Anyways, if you're interested in a simple-minded 'dictionary' type of example in Fortran for the case you present in the original post, please comment and I can post one here; Stefano Zaghi and others will most likely have far more advanced 'classes' on GitHub, etc. that you can employ for your needs too.
>
> I'll be most eager to see if you are able to follow-up as I request above with Python and Fortran minimal working examples of your use case and your analysis (however brief) on the 'easier way' regarding these two approaches.
>
> Most Sincerely,

We can offer some sort of generic containers (list, dictionary and hash table, soon quad/oct trees), but not "introspection". Pascal should go with Python is he want a very concise and maintainable keywords processor.

My best regards.

Stefano Zaghi

unread,
Oct 18, 2016, 10:21:00 AM10/18/16
to
Sorry,

I forget to post the input file

---input
worker1
worker2
worker3
worker4
---end input

My best regards.

dpb

unread,
Oct 18, 2016, 10:58:14 AM10/18/16
to
That is, for much of his universe, the statement may well still be so... :)

FortranFan

unread,
Oct 18, 2016, 11:41:53 AM10/18/16
to
On Tuesday, October 18, 2016 at 10:16:20 AM UTC-4, Stefano Zaghi wrote:

> ..
>
> I think that Pascal is a "wiseman" for select Python for such a task. However, my reasons to flavor Python are not strictly related to its great support for generic containers (that we mimic, in very limited fashion, in Fortran) rather Python is really "introspective". I cannot reproduce exactly the Pascal's scenario, but on the base of what we know, please consider the following complete Python program
>
> ..
>
> This is really "introspection": I am obtaining a function by a string.
>
> To my knowledge this is not possible in pure Fortran (that is not an interpreted language). Running the above code you obtain also fancy alert when a particular keyword is not yet support, i.e.
>
> ..


Thanks much, Stefano - that's simply brilliant!

I guess it will now be useful if Pascal can the "why's", the "what's", and the "how's" to inform us about the 'easier' part!

With me being totally illiterate about Python, it just appears there is a lot of text (thus a lot of typing) with a lot of keyboard symbols (the double underscores which is always confusing to me, the parentheses, the double dashes, etc.) needed to complete the 'introspection' [thus possibly some effort to get it right], plus the need for input file i.e., more user interaction and chances to go wrong.

With Fortran, SAY an abstract dictionary 'class' and an user-extended 'class' for 'procedure pointer' and keyword pairs are ALREADY available e.g., in a scenario where a coder like Pascal wants to do such things often. Then the code can simply be like this, right?

-- begin example --
module m

use procs_m, only: Isub, worker1, worker2, worker3
use procdict_m, only : procdict_t ! as in a user supplied library

implicit none

private

type(procdict_t), save :: dict
logical, save :: dict_loaded = .false.

public :: worker

contains

subroutine worker( keyword, msg )

character(len=*), intent(in) :: keyword
character(len=*), intent(in) :: msg

!.. Local variables
procedure(Isub), pointer :: proc

if ( .not. dict_loaded ) then

call dict%load( "worker1", worker1 )
call dict%load( "worker2", worker2 )
call dict%load( "worker3", worker3 )

dict_loaded = .true.

end if

proc => dict%getproc( keyword )
if ( associated(proc) ) then
call proc( keyword, msg )
else
print *, "invalid keyword of " // keyword
end if

return

end subroutine worker

end module m
program p

use m, only : worker

implicit none

character(len=:), allocatable :: keyword
character(len=*), parameter :: Message = "Keep it simple!"

keyword = "worker3"
call worker( keyword, Message )

keyword = "worker1"
call worker( keyword, Message )

keyword = "worker2"
call worker( keyword, Message )

keyword = "workerfoo"
call worker( keyword, Message )

stop

end program p
-- end example --

Upon execution, it should give
-- begin --
worker3 gets the message: Keep it simple!
worker1 gets the message: Keep it simple!
worker2 gets the message: Keep it simple!
invalid keyword of workerfoo

Process returned 0 (0x0) execution time : 0.016 s
-- end --

Now here's the code for the simple-minded 'dictionary' that a library developer would put together ONCE and it's done!

-- begin library code --
module dict_m

implicit none

private

type :: key_item_t
private
character(len=:), allocatable :: m_key
class(*), pointer :: m_item => null()
contains
private
final :: clean_key_item
end type key_item_t

integer, parameter :: MAXCHUNK = 10

type, abstract, public :: dict_t
private
type(key_item_t), allocatable :: m_keyitempairs(:)
integer :: m_numpairs = 0
contains
private
procedure, pass(this) :: load_keyitem_pair
procedure, pass(this), public :: item => getitem_key
generic, public :: load => load_keyitem_pair
end type dict_t

contains

impure elemental subroutine clean_key_item( this )

type(key_item_t), intent(inout) :: this

if ( associated(this%m_item) ) then
deallocate( this%m_item )
end if
deallocate( this%m_key )

return

end subroutine clean_key_item

subroutine load_keyitem_pair( this, key, item, lbase )

!.. Argument list
class(dict_t), intent(inout) :: this
character(len=*), intent(in) :: key
class(*), intent(in) :: item
logical, intent(in) :: lbase

if ( lbase ) then

if ( allocated(this%m_keyitempairs) ) then
if ( this%m_numpairs == size(this%m_keyitempairs) ) then
! elided is the action to extend the data by an additional CHUNK
end if
else
allocate( this%m_keyitempairs(MAXCHUNK) )
end if

this%m_numpairs = this%m_numpairs + 1
this%m_keyitempairs(this%m_numpairs)%m_key = key

allocate( this%m_keyitempairs(this%m_numpairs)%m_item, source=item )

end if

return

end subroutine load_keyitem_pair

function getitem_key( this, keyword, lbase ) result( item )

!.. Argument list
class(dict_t), intent(in) :: this
character(len=*), intent(in) :: keyword
logical, intent(in) :: lbase
!.. function result
class(*), pointer :: item

!.. Local variables
integer :: i
logical :: key_found

item => null()
if (.not. lbase) return

! Elided is advanced keyword search algorithms
! Simple linear search only for illustration
key_found = .false.
Loop_I: do i = 1, this%m_numpairs
if ( keyword == this%m_keyitempairs(i)%m_key ) then
item => this%m_keyitempairs(i)%m_item
key_found = .true.
exit Loop_I
end if
end do Loop_I

if ( .not. key_found ) then
! error stop?
return
end if

return

end function getitem_key

end module dict_m

module procs_m

implicit none

abstract interface
subroutine Isub( keyword, msg )
implicit none
!.. Argument list
character(len=*), intent(in) :: keyword
character(len=*), intent(in) :: msg
end subroutine Isub
end interface

contains

subroutine worker1( keyword, msg )

include "i.f90"

end subroutine worker1

subroutine worker2( keyword, msg )

include "i.f90"

end subroutine worker2

subroutine worker3( keyword, msg )

include "i.f90"

end subroutine worker3

end module procs_m

module procdict_m

use dict_m, only : dict_t
use procs_m, only : Isub

implicit none

private

type :: procwrapper_t
private
procedure(Isub), nopass, pointer :: m_proc => null()
end type procwrapper_t

type, extends(dict_t), public :: procdict_t
private
contains
private
procedure, pass(this) :: load_keyproc_pair
procedure, pass(this), public :: getproc => getproc_key
generic, public :: load => load_keyproc_pair
end type procdict_t

contains

subroutine load_keyproc_pair( this, key, proc )

!.. Argument list
class(procdict_t), intent(inout) :: this
character(len=*), intent(in) :: key
procedure(Isub) :: proc

!.. Local variables
type(procwrapper_t), allocatable :: wrapper

allocate( wrapper )
wrapper%m_proc => proc

call this%load( key, wrapper, lbase=.true. )

return

end subroutine load_keyproc_pair

function getproc_key( this, keyword ) result( proc )

!.. Argument list
class(procdict_t), intent(in) :: this
character(len=*), intent(in) :: keyword
!.. function result
procedure(Isub), pointer :: proc

!.. Local variables
class(*), pointer :: wrapper

proc => null()
wrapper => this%item(keyword, lbase=.true.)

if ( associated(wrapper) ) then

select type ( wrapper )
type is ( procwrapper_t )
proc => wrapper%m_proc
class default
! error stop?
end select

end if

return

end function getproc_key

end module procdict_m
-- end library code --

For the sake of a discussion and only that (readers: note I'm not trying to start any language wars please), it would appear:

1) Fortran code is *similarly* easy to put together, if not simpler (my own bias!)

2) Fortran code can be expressive and more human-readable with fewer language tokens which are mostly English-like and there are few 'strange' symbols coming into play - as shown above albeit with a simple-minded algorithm,

3) In order to extend the program with more keywords, the coder only needs to supply the worker procedure which has to be done no matter what the paradigm is, and then has to do a bit of work in just ONE more place - the equivalent of the dictionary load step in module m above and that's it.

There is, of course, the other difference that Fortran is a compiled language whereas Python is an interpreted one that has been preferred by many casual coders since the days of BASIC. But isn't that a separate issue? e.g., can one not offer interpreter that work with 'modern Fortran' syntax?

I guess I'm still trying to understand the 'easier way' question in the original post, it's even more confusing for me, now that Pascal has brought up Python! That is, what all would coders think are the aspects make certain approaches 'easier' or 'more suited'?

Thanks again,

Stefano Zaghi

unread,
Oct 18, 2016, 12:14:27 PM10/18/16
to
Dear FortranFan,

Il giorno martedì 18 ottobre 2016 17:41:53 UTC+2, FortranFan ha scritto:
> I guess it will now be useful if Pascal can the "why's", the "what's", and the "how's" to inform us about the 'easier' part!

:-)

> With me being totally illiterate about Python, it just appears there is a lot of text (thus a lot of typing) with a lot of keyboard symbols (the double underscores which is always confusing to me, the parentheses, the double dashes, etc.) needed to complete the 'introspection' [thus possibly some effort to get it right], plus the need for input file i.e., more user interaction and chances to go wrong.

I am very sorry, your bad feeling is due to only my bad OCD... there are many lines not useful for the purposes of illustrating the introspection, e.g. the command line argument parsing. Moreover, the verbosity of the syntax, i.e. the (ab)use of underscores, is to be imputed only to me (again to my OCD): in Python the underscores are used (also) for name space mangling, in particular double leading and trailing underscores creates "magic" objects or attributes that live in user-controlled namespace. Such names should not be used, but for very simple script I like to use them because this ensures me that functions defined in the same module, e.g. the workers functions, do not touch that variables that are (otherwise) global to the module. Indeed, I should have to trim out at least the last underscore to be compliant with PEP8, but I was lazy. In conclusion, the above Python script could be much more concise and elegant than my bad work.

For the "introspection" there is no need of underscores abuse, you need only the wonderful built-in "globals" that carry to you the function getting method "get", that is without my underscore-based-pollution:

workers = globals().copy()
workers.update(locals())
for key in keywords:
worker = workers.get(key)


> With Fortran, SAY an abstract dictionary 'class' and an user-extended 'class' for 'procedure pointer' and keyword pairs are ALREADY available e.g., in a scenario where a coder like Pascal wants to do such things often. Then the code can simply be like this, right?... elided a lot

I have to start the daily trip to come back to home now, sorry, I'll study your code tomorrow, it is very very interesting. Anyhow, I also thought to suggest to Pascal an OOP solution, but I guess he refuse the idea, it seeming more complex rather easier (and for good reasons, if the task is really simple as the same line of my Python toy). See you tomorrow.

My best regards.

Ron Shepard

unread,
Oct 18, 2016, 12:49:14 PM10/18/16
to
On 10/18/16 3:39 AM, Stefano Zaghi wrote:
> Now we can discuss which is preferable over other: I prefer the "if" for the aforementioned reasons, why you prefer the "goto" one?

I'm not sure I "prefer" the computed GOTO version, but the IF version
has repeated N test-and-branch instructions that are all executed
regardless of the value of the key. That is, the high-level fortran code
does not reflect well on the actual desired sequence of instructions.
The computed GOTO code always has a single test and branch, regardless
of the value of the key, which does match well with the actual sequence
of instructions.

Or said a different way, in the sequence

if (keyword<2) call worker1(key=keyword)
if (keyword<3) call worker2(key=keyword)
if (keyword<4) call worker3(key=keyword)
if (keyword<5) call worker4(key=keyword)

When keyword==1, then only the first test is essential, the results of
the remaining tests are then known ahead of time and in principle need
not be executed. When keyword==4, then all four tests must be executed
to achieve the correct flow of execution, whereas only a single test and
branch is required with the computed GOTO code.

In a similar way, the SELECT CASE version takes a sequence of N
statements and maps them into separate branches of N*(N+1)/2 total
statements in the fortran code, each duplicated up to N times and
duplicated N/2 average times, so it also does not match well with the
actual desired sequence of instructions, and maintenance of those
redundant lines or code presents additional problems for the programmer(s).

Of course beauty is in the eyes of the beholder, but in these situations
the computed GOTO seems to be the most aesthetically pleasing code, in
addition to the practical advantages described above.

$.02 -Ron Shepard

Stefano Zaghi

unread,
Oct 18, 2016, 3:04:53 PM10/18/16
to
Dear Ron,

Il giorno martedì 18 ottobre 2016 18:49:14 UTC+2, Ron Shepard ha scritto:
> I'm not sure I "prefer" the computed GOTO version, but the IF version
> has repeated N test-and-branch instructions that are all executed
> regardless of the value of the key...

You are absolutely right, I was conscious of that, but how big is the overhead I cannot say, I think it is very problem dependent. Tomorrow I'll to quantify in the OP scenario similarity.

> In a similar way, the SELECT CASE version takes a sequence of N
> statements and maps them into separate branches of N*(N+1)/2 total
> statements in the fortran code, each duplicated up to N times and
> duplicated N/2 average times, so it also does not match well with the
> actual desired sequence of instructions, and maintenance of those
> redundant lines or code presents additional problems for the programmer(s).

I would not try to implement your "flushed-flow" branching by means of select case just because it surely has more overhead and it surely results in more cumbersome branching flow than the "if" based one. However, aside any quantification of the overhead involved, I still prefer the "if" based flow. If the overhead is really huge I prefer to redesing the branching maybe by means of OOP patterns, but goto has to many cons thus I would consider it only if the speedup is really relevant for the case in hand.

> Of course beauty is in the eyes of the beholder, but in these situations
> the computed GOTO seems to be the most aesthetically pleasing code, in
> addition to the practical advantages described above.

On the contrary, I think that also from an aestetical point of view, the goto branch is bad: as Ian observed, the goto instruction tells me nothing about the branching is, goto allows in general to jump everywhere, whereas the if-baseflow is intrinsecally linear, moreover it has one less statement, i.e. the goto itself :-) Clearly my eyes have to much myopia with respect yours :-)

My best regards.

FortranFan

unread,
Oct 18, 2016, 3:44:58 PM10/18/16
to
On Tuesday, October 18, 2016 at 1:33:25 AM UTC-4, Ron Shepard wrote:

> ..
>
> But there is one situation that seems to be better with computed GOTO
> than SELECT CASE. Something like this:
>
> goto (1,2,3,4), ikey
> 1 call s1()
> 2 call s2()
> 3 call s3()
> 4 call s4()
> ...
>
> ..

Ron, Stefano:

SELECT CASE and IF THEN ELSE need NOT be the only option to decompose complex constructs that might possible spaghetti-like structure into more expressive code that makes it easier to understand for someone else (including the author her(him)self at a future date); consider BLOCK with EXIT construct too.

I use BLOCK with EXIT quite a bit to help me simplify convoluted constructs.

For the example shown by Ron, assuming the order of execution doesn't matter, as an alternative consider:

blk: block

call s4()
if ( (ikey >= 1).and.(ikey <= 4) then
exit blk
end if

call s3()
if ( (ikey >= 2).and.(ikey <= 4) then
exit blk
end if

call s2()
if ( (ikey >= 3).and.(ikey <= 4) then
exit blk
end if

call s1()
if ( ikey == 4 ) then
exit blk
end if

end block blk

which, I think, makes the intent a bit more clear to a reader relative to the computed GOTO option, at least for newer engineers who didn't "grow up" with the latter feature.

In the case of computed GOTO, I know there have been coders who forgot "If the value of the expression is less than 1 or greater than the number of labels in the list, control is transferred to the next executable statement or construct following the computed GO TO statement." and errors were introduced as a result.
It is loading more messages.
0 new messages