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

PUREity of F2015 routines when called by F2008 code

407 views
Skip to first unread message

Hirst, Adam Phillip

unread,
Dec 13, 2016, 7:11:08 AM12/13/16
to
Hi all,

I'm making some straightforward changes to the F90 library PPPACK[1],
specifically extracting the routines I require and modifying them so
that they may be declared and used as PURE (and thus, in CONCURRENT
loops and so on, as I am investigating ways to improve the performance
of my current project). Nothing complicated, but I wanted to share a
comment or two, and also ask a question.

The routines in the source file are "naked", i.e. not encapsulated in a
module, and of course some of them call each other, but none of them
declare explicit interfaces to each other (which works fine as long as
there are no special circumstances to take into account). Some of them
have I/O when errors occur, then calling STOP, and others declare some
SAVE variables to cache results from previous calls (which only acts as
an optimisation for these routines when they're called with a variable
which is gradually increased or decreased, something I do not do).

After removing these SAVE attributes, declaring explicit INTENTs, and
then setting the PURE keyword, I noticed that compilation only completed
successfully when I either encapsulated the routines in a module, or
declared explicit PURE interfaces to routines called from each other.
I'm using gfortran, which now supports the F2015 feature whereby ERROR
STOP statements are permitted in PURE routines, and used this to replace
the I/O calls.

By default I always compile my projects according to one of the -std
options in gfortran, currently -std=f2008 unless I have a good reason to
do otherwise, but if I wish to link from my current project to my
modified PPPACK builds, this raises an obvious question:

As PURE in F2008 does NOT permit ERROR STOP statements, but F2015 does,
is it valid to declare in an INTERFACE block in an F2008 project that an
external subroutine is PURE when that external routine itself contains
ERROR STOP statements?

Obviously this issue goes away if I decide to compile my project without
the -std flag, and AFAIK there is currently no -std=f2015 flag in
gfortran, but it'd nice to get some opinions and comments about this.

Best regards,
Adam

[1] https://people.sc.fsu.edu/~jburkardt/f_src/pppack/pppack.html
BSPLVB, BSPLVD, INTERV, BSPLPP, BSPP2D, PPVALU

Marco

unread,
Dec 13, 2016, 7:50:13 AM12/13/16
to
I don't really have much to say about this, except that this seems a
meta-standard question: how are two standards supposed to coexist in
the same code - very interesting!

> Obviously this issue goes away if I decide to compile my project without
> the -std flag, and AFAIK there is currently no -std=f2015 flag in
> gfortran, but it'd nice to get some opinions and comments about this.

For errors inside pure functions I use the following:

!> Stop the execution, can be called in a pure procedure
pure subroutine my_pure_abort()
! Something to (hopefully) trigger a core dump
real :: x
x = x/0.0
end subroutine my_pure_abort

You could have such a subroutine to isolate the call to "ERROR STOP"
and there you could easily switch between the 2015 ERROR STOP and the
95 version x/0.0, depending on how much this feature is supported by a
certain compiler.

Marco

FortranFan

unread,
Dec 13, 2016, 9:16:23 AM12/13/16
to
On Tuesday, December 13, 2016 at 7:11:08 AM UTC-5, Hirst, Adam Phillip wrote:

> .. an obvious question:
>
> As PURE in F2008 does NOT permit ERROR STOP statements, but F2015 does,
> is it valid to declare in an INTERFACE block in an F2008 project that an
> external subroutine is PURE when that external routine itself contains
> ERROR STOP statements?
>
> ..


Just my 2 cents worth: with the commercial compiler, I simply use the latest setting that my code corresponds to, as in -stand:f15. If I recall correctly, gfortran quickly started supporting -std:f2008ts compiler option once technical specifications of 29113 and 18508 were implemented along with the 2008 standard features, so perhaps you can consider requesting the gfortran team to support -std:f2015 as well since Fortran 2015 items are being added now. You can then use -std:f2015 to move beyond your current dilemma, that will be one of my suggestions.

Separately, my suggestion will also be to encapsulate your version of PPPACK in your 'class library' along the lines of the wonderful work by Dr. Stefano Zaghi on various libraries c.f. https://github.com/szaghi

The class can 'contain' methods - type-bound procedures - for all the compute routines as PURE (as you have them now) and this class can have a public setter method which allows callers to provide procedure pointer to an error handler procedure (that can be PURE too), with your class containing a default error handler. This default handler may only do something simple such as 'store' some error code and error text into some private member (derived type components) of this class which a caller can fetch with getter methods as needed. Now the caller can override the default by providing its own handler and this handler can include 'ERROR STOP'. That is, my view is a 'library' system such as one's own PPPACK shouldn't, by itself, ever perform an 'abort', that task should be left up to callers. Also, if the library build is a separate project from the caller, you can use separate -std settings for them, thereby avoiding the coexistence issue of the two standards.

Hirst, Adam Phillip

unread,
Dec 13, 2016, 10:09:17 AM12/13/16
to
I mentioned earlier about encapsulating the routines from PPPACK into a
module as one of the two ways for the interfaces between the routines in
the library to be generated, and this modified version of pppack.f90
builds fine as a library (dll/so).

However, if I then try to link to that from my main code (I have a
PPPACK project and "my" project both as parts of a Code::Blocks
workspace), my main code fails to resolve the symbols.

I was always under the impression that you were indeed allowed to use
MODULEs in libraries, but I tried Googling for this and I can't seem to
find the right keywords to give me anything relevant (and my copy of
Modern Fortran Explained is currently in a different country.

What is it exactly hat szaghi is doing that lets his libraries export
derived types or subroutines when it's all inside modules?

Cheers,
Adam

Arjen Markus

unread,
Dec 13, 2016, 10:13:18 AM12/13/16
to
Well, modules can be stored in libraries, that is not the point. But whether the routines reside in libraries or in separate object files, the compiler needs to be aware of them and that is where USE statements and .mod files come into play.

You are USEing the modules, right? And the compiler can find the .mod files? Just checking :).

Regards,

Arjen

Hirst, Adam Phillip

unread,
Dec 13, 2016, 10:25:56 AM12/13/16
to
Well, I tried USEing the module by name, but the compiler/linker failed
to find the modules in question. I'm not sure whether this is a
deficiency of my code or of whatever it is that Code::Blocks does, but
later on I will make a sample C::B workspace with a dummy "library"
project and see what I can figure out. (Sadly I can't share my own code)

Cheers, Adam

FortranFan

unread,
Dec 13, 2016, 10:28:27 AM12/13/16
to
On Tuesday, December 13, 2016 at 10:09:17 AM UTC-5, Hirst, Adam Phillip wrote:

> ..
>
> I mentioned earlier about encapsulating the routines from PPPACK into a
> module as one of the two ways for the interfaces between the routines in
> the library to be generated, and this modified version of pppack.f90
> builds fine as a library (dll/so).
>
> However, if I then try to link to that from my main code (I have a
> PPPACK project and "my" project both as parts of a Code::Blocks
> workspace), my main code fails to resolve the symbols.
>
> I was always under the impression that you were indeed allowed to use
> MODULEs in libraries, but I tried Googling for this and I can't seem to
> find the right keywords to give me anything relevant (and my copy of
> Modern Fortran Explained is currently in a different country.
>
> ..

Assuming you are on a Linux OS, I don't know the details but perhaps this thread will help:
https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/704350

But on Windows OS, I prefer to use definition files for the export symbols from a DLL library and specify it to the linker to create a .lib file that the caller can use:
https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/4/html/Using_ld_the_GNU_Linker/win32.html

Note these are all linker and OS-specific details and are effectively independent of Fortran/C/C++ and any 'library design' suggestions I made previously.






Hirst, Adam Phillip

unread,
Dec 13, 2016, 10:32:24 AM12/13/16
to
On 13.12.2016 16:28, FortranFan wrote:
> On Tuesday, December 13, 2016 at 10:09:17 AM UTC-5, Hirst, Adam Phillip wrote:
>
>> ..
>>
>> I mentioned earlier about encapsulating the routines from PPPACK into a
>> module as one of the two ways for the interfaces between the routines in
>> the library to be generated, and this modified version of pppack.f90
>> builds fine as a library (dll/so).
>>
>> However, if I then try to link to that from my main code (I have a
>> PPPACK project and "my" project both as parts of a Code::Blocks
>> workspace), my main code fails to resolve the symbols.
>>
>> I was always under the impression that you were indeed allowed to use
>> MODULEs in libraries, but I tried Googling for this and I can't seem to
>> find the right keywords to give me anything relevant (and my copy of
>> Modern Fortran Explained is currently in a different country.
>>
>> ..
>
> Assuming you are on a Linux OS, I don't know the details but perhaps this thread will help:
> https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/704350

I'm actually on Windows, but I'm using cbfortran to handle the build
system (GCC, provided by MinGW-MSYS2).

> But on Windows OS, I prefer to use definition files for the export symbols from a DLL library and specify it to the linker to create a .lib file that the caller can use:
> https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
> https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/4/html/Using_ld_the_GNU_Linker/win32.html
>
> Note these are all linker and OS-specific details and are effectively independent of Fortran/C/C++ and any 'library design' suggestions I made previously.

Are you able to comment then on how the "library design" suggestions
from earlier come into play, when (as I mention) the compilation fails
to see the routines in the MODULEs in the library?

Cheers, Adam

FortranFan

unread,
Dec 13, 2016, 10:33:48 AM12/13/16
to
On Tuesday, December 13, 2016 at 10:25:56 AM UTC-5, Hirst, Adam Phillip wrote:

> ..
>
> Well, I tried USEing the module by name, but the compiler/linker failed
> to find the modules in question. ..


As you may have noticed on this forum and elsewhere, 'USEing' is relevant to Fortran and the mod files are needed by the *compiler* to make it happen.

However a *linker*, which is separate from a Fortran compiler, usually needs .lib (or .so files on Linux, I think not sure) to create the executable. See the online links I posted at 10:28 am, Dec 13, 2016 for further details.

Arjen Markus

unread,
Dec 13, 2016, 10:47:34 AM12/13/16
to
As FortranFan notices too, that is the cause of the problem.

For the compiler it is necessary to known which module the routines come from. For the linker to recognise them the actual names in the object file are decorated in such a way that they are associated with the module.

Consider this:
In one routine you use the routine mysub, which is not contained in a module, because it is coming from a FORTRAN 77-style library.
In another routine you use a completely unrelated routine mysub which _is_ contained in a module. These two may have the same name in the Fortran source, but for the linker they are different entities.

Hence the USE statement - the consequences for the linker usually do not need to concern the ordinary Fortran programmer, but they are necessary for the compiler and the linker to cooperate and to do the right thing.

I do not use CodeBlocks, but surely you can set the path to the module files?

Regards,

Arjen

Hirst, Adam Phillip

unread,
Dec 13, 2016, 10:49:33 AM12/13/16
to
I'm trying to digest the information in the links that FortranFan
provided, but until then, can you at least confirm whether or not this
would be the same as specifying an additional include directory? If not,
I don't think C::B has an explicit option for this, other than the text
field where you can specify /any/ options to the compiler/linker...

>
> Regards,
>
> Arjen
>

Hirst, Adam Phillip

unread,
Dec 13, 2016, 11:07:27 AM12/13/16
to
OK, I think I know what's going on.

The .mod file is output into the "objects" directory, the same place the
the .o goes (which was used to generate the .dll/.so). Indeed, I *think*
C::B treats them both as "objects" and thus their target directory is
governed by the same setting.

What needs to happen is that the compiler/linker sees this .mod file,
and then I am able to USE my MODULE-version of PPPACK as expected.

What I need to do is work out the best way in the C::B project framework
to either point the compiler/linker directly to where this .mod file
gets generated, or to ensure that the .mod file gets put somewhere
sensible that the compiler/linker then looks.

Thanks for the space in which to organise my thoughts, and if I work out
something "clean", I'll try to remember to post back with advice that
hopefully any other (current or prospective) C::B-Fortran users might
find useful.

Cheers,
Adam

Stefano Zaghi

unread,
Dec 13, 2016, 11:09:53 AM12/13/16
to
Dear Adam,

I agree as always with FortranFan and Arjen: "module" is great enchantment of "modern" Fortran, it is worth to use it. "Modularization" is of great help for a lot of good reasons. However, the way it has been "implemented" by Fortran is somehow frustrating (for me), in particular, the compiled .mod files (that are generated after the compilation of a module) are in no-way "portable", they are not standardized and even with the same compiler you can have different .mod formats accordingly to different versions of the same compiler. This is frustrating because inhibits the distribution of compiled libraries: say you have a library pre-built for a target architecture and you want to distribute to your users a compiled .a (or .so) then you have to distribute also the .mod that are so compiler-dependent that you must also ensure that the user has the same version you have used for building your library... this is painful and let me to think that the true portable distribution can be achieved by only distributing the sources: this is good for me, but for other it could be not, moreover you put on the shoulders of the user the steps of building your libraries that can be problematic with modules...

This introduction is tailored to let you aware that modules are great, but introduce a "building complexity": modules introduce a "compilation cascade or hierarchy", if a "unit" use a module that module must be compiled before the unit... this means that our old addiction to build a "blob" of non-modules sources cannot be used if modules are exploited. Consider the following example:

---start example
module bar_module
use iso_fortran_env
implicit none

integer(int32), parameter :: BAR=1_int32
end module bar_module

module baz_module
use bar_module, BAZ=>BAR
end module bar_module

program foo
use baz_module
implicit none
print*, BAZ
end program foo
---end example

The module "bar_module" must be compiled before "baz_module"...

Modern IDE like Visual Studio & Co. can handle such "dependencies" almost auto-magically, but I am not sure that Code::blocks can. If you have no access to an automatic-building tool, you can try my own, https://github.com/szaghi/FoBiS

FoBiS should be able to build almost all by means of a "FoBiS.py build" command :-), however I never used it on Windows (only GNU Linux and OSX), but it is supposed to be cross-platform.

My best regards.

FortranFan

unread,
Dec 13, 2016, 11:30:17 AM12/13/16
to
On Tuesday, December 13, 2016 at 10:32:24 AM UTC-5, Hirst, Adam Phillip wrote:

> ..
>
> Are you able to comment then on how the "library design" suggestions
> from earlier come into play, when (as I mention) the compilation fails
> to see the routines in the MODULEs in the library?
> ..


Say you have a Fortran 'library' in a module as follows:

-- begin libfoo.f90 --

module libfoo

implicit none

private

public :: foo

contains

subroutine foo()

print *, "libfoo1 says Hello World!"

return

end subroutine foo

end module libfoo

-- end libfoo.f90 --

that will be invoked by a caller program like so:

-- begin p.f90 --
program p

use libfoo, only : foo

implicit none

call foo()

stop

end program p
-- end p.f90 --

1. I would then package the library, say in foo.dll, with a foo.cbp project in Code::Blocks. This project will then asked be to 'create an import library' file using a foo.def file (see XML project file below). And it will also create .a archive file.

2. The caller will be in a separate project, say p.cbp. This project will make use of .mod and .a files. etc. created by foo.cbp project.

3. If necessary, one can make them part of the same workspace, say p.workspace, with dependencies set i.e., p project depends on foo project.

So, here's the definition file for the library project, foo.cbp:

-- begin libfoo.def --
LIBRARY foo
EXPORTS
__libfoo_MOD_foo @1
-- end foo.def --

here's the XML foo.cbp file you can use with Code::Blocks:

-- begin foo.cbp --
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="foo" />
<Option pch_mode="2" />
<Option compiler="?? - use C::B to pick your compiler" />
<Build>
<Target title="Debug">
<Option output="Debug/GNU/foo" prefix_auto="1" extension_auto="1" />
<Option object_output="Debug/GNU/" />
<Option type="3" />
<Option compiler="?? - use C::B to pick your compiler" />
<Option createStaticLib="1" />
<Compiler>
<Add option="-Wall" />
<Add option="-g" />
<Add option="-DBUILD_DLL" />
<Add option="-fPIC" />
</Compiler>
</Target>
<Target title="Release">
<Option output="Release/GNU/foo" prefix_auto="1" extension_auto="1" />
<Option object_output="Release/GNU/" />
<Option type="3" />
<Option compiler="?? - use C::B to pick your compiler" />
<Option createStaticLib="1" />
<Option projectLinkerOptionsRelation="2" />
<Compiler>
<Add option="-O2" />
<Add option="-Wall" />
<Add option="-DBUILD_DLL" />
<Add option="-fPIC" />
</Compiler>
<Linker>
<Add option="-s" />
</Linker>
</Target>
</Build>
<Linker>
<Add option="sor\libfoo.def" />
</Linker>
<Unit filename="sor/libfoo.f90">
<Option weight="0" />
</Unit>
<Extensions>
<code_completion />
<envvars />
<debugger />
<lib_finder disable_auto="1" />
</Extensions>
</Project>
</CodeBlocks_project_file>
-- end foo.cbp --

Here's the XML project file for caller program, p.cbp:

-- begin p.cbp --
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="p" />
<Option pch_mode="2" />
<Option compiler="?? - use C::B to pick your compiler" />
<MakeCommands>
<Build command="" />
<CompileFile command="" />
<Clean command="" />
<DistClean command="" />
<AskRebuildNeeded command="" />
<SilentBuild command=" &gt; $(CMD_NULL)" />
</MakeCommands>
<Build>
<Target title="Debug">
<Option output="Debug/GNU/p" prefix_auto="1" extension_auto="1" />
<Option object_output="Debug/GNU/" />
<Option type="1" />
<Option compiler="?? - use C::B to pick your compiler" />
<Compiler>
<Add option="-Wrealloc-lhs-all" />
<Add option="-Wrealloc-lhs" />
<Add option="-Wimplicit-interface" />
<Add option="-Wconversion" />
<Add option="-Warray-temporaries" />
<Add option="-pedantic" />
<Add option="-W" />
<Add option="-Wextra" />
<Add option="-Wall" />
<Add option="-fcheck=all" />
<Add option="-g" />
</Compiler>
<Linker>
<Add directory="Debug/GNU/" />
</Linker>
</Target>
<Target title="Release">
<Option output="Release/GNU/p" prefix_auto="1" extension_auto="1" />
<Option object_output="Release/GNU/" />
<Option type="1" />
<Option compiler="?? - use C::B to pick your compiler" />
<Compiler>
<Add option="-O2" />
<Add option="-Warray-temporaries" />
<Add option="-Wextra" />
</Compiler>
<Linker>
<Add directory="Release/GNU/" />
</Linker>
</Target>
</Build>
<Linker>
<Add library="libfoo.a" />
</Linker>
<Unit filename="sor/p.f90">
<Option weight="0" />
</Unit>
<Extensions>
<code_completion />
<envvars />
<debugger />
<lib_finder disable_auto="1" />
</Extensions>
</Project>
</CodeBlocks_project_file>
-- end p.cbp --

And the XML workspace file if you decide to work with it:

- begin p.workspace --
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_workspace_file>
<Workspace title="Workspace">
<Project filename="p.cbp">
<Depends filename="foo.cbp" />
</Project>
<Project filename="foo.cbp" />
</Workspace>
</CodeBlocks_workspace_file>
-- end p.workspace --

Notice the options in Code:Blocks' .cbp (XML) files toward

a) <Option output="Debug/GNU/foo" .. /> and <Option object_output=".." />. You can use these to control where files go,

b) <Option createStaticLib="1" />. You likely already have this.

c) look under all the XML tags for <Linker>
1) <Add option="sor\libfoo.def /> in foo.cbp file
2) <Add library="libfoo.a" /> in p.cbp file

Perhaps the best way to understand it all will be for you to create a folder, say C:\foo and a subfolder C:\foo\sor:

1) then save the *.cbp files and p.workspace above in C:\foo,
2) save the *.f90 and libfoo.def in C:\foo\sor
3) open p.workspace using Code::Blocks, fix the compiler version details on your installation, and let it rip.

FortranFan

unread,
Dec 13, 2016, 4:29:50 PM12/13/16
to
On Tuesday, December 13, 2016 at 11:30:17 AM UTC-5, FortranFan wrote:

> ..
>
> Perhaps the best way to understand it all will be for you to create a folder, say C:\foo and a subfolder C:\foo\sor:
>
> 1) then save the *.cbp files and p.workspace above in C:\foo,
> 2) save the *.f90 and libfoo.def in C:\foo\sor
> 3) open p.workspace using Code::Blocks, fix the compiler version details on your installation, and let it rip.

@Adam,

Please note I'm not suggesting you need to work with XML files directly, normally you would set all this up within the Code::Blocks IDE by making use of its user-interface (UI) facilities in the various forms and fields it provides.

The long description in my previous post was simply to illustrate to you all the 'wiring' behind the scenes and to give you something within the *constraints of this text-based forum*, so you can get going.

Once you understand the Microsoft and GCC related stuff from the two online sites I'd supplied earlier (the one from MSDN and the other from Access Redhat.com), you will figure out in Code::Blocks IDE what to do. Then when you open in Code::Blocks the p.workspace file I list upthread (with foo.cbp, p.cbp, p.f90, libfoo.f90, and libfoo.def files all saved on your workstation as I suggested), you will see exactly what's going within the IDE and you will be able to make all the connections.

Once you do, you would never again need to look the XML project files expect perhaps out of curiosity or unexpected system errors.

There is still a point I want to reiterate about Fortran code design toward libraries, but I will wait until you have moved past the 'mechanics' of linking and using DLLs in Code::Blocks IDE.

Good luck,

FortranFan

unread,
Dec 13, 2016, 5:10:05 PM12/13/16
to
On Tuesday, December 13, 2016 at 11:30:17 AM UTC-5, FortranFan wrote:

>
> .. This project will then asked be to 'create an import library' file using a foo.def file ..
>
> So, here's the definition file for the library project, foo.cbp:
>
> -- begin libfoo.def --
> LIBRARY foo
> EXPORTS
> __libfoo_MOD_foo @1
> -- end foo.def --
>
> ..

Forgot to mention: you will notice in the above that when a procedure named 'foo' is included in a Fortran module named 'libfoo', normally the *decorated* symbol for it that needs to be *exported* from the DLL (if built with GCC/gfortran compiler) is __libfoo_MOD_foo.

Note if you apply BIND(C, name="xx") attribute in Fortran to procedure toward interoperability with C, then the exported symbol will be xx itself.

Damian Rouson

unread,
Dec 14, 2016, 12:33:04 AM12/14/16
to
On Tuesday, December 13, 2016 at 4:11:08 AM UTC-8, Hirst, Adam Phillip wrote:
>
> I'm using gfortran, which now supports the F2015 feature whereby ERROR
> STOP statements are permitted in PURE routines, and used this to replace
> the I/O calls.

Just in case it's of interest, gfortran also added a related new Fortran 2015
feature: non-constant error stop codes. This is especially useful in the
context of PURE procedures, wherein ERROR STOP is the only allowable
form of I/O. Exploiting this new capability requires using a build of the
pre-release GCC 7.0.0 trunk. I've used it in a build dated 20161112.

Damian

Hirst, Adam Phillip

unread,
Dec 14, 2016, 2:16:46 AM12/14/16
to
Awesome! Could you maybe give a trivial example of the usage? Also, as
was asked elsewhere in this thread, are there plans to introduce a flag
-std=f2015 in the near future?

Cheers, Adam

paul.rich...@gmail.com

unread,
Dec 14, 2016, 3:01:28 PM12/14/16
to
This is now Bug 78797 - It is time perhaps to implement -std=f2015

It will take a little while to sort this one out since there are rather more obsoletes and deletions than implementation of new F2015 features thus far.

We'll get to it :-)

Paul

Damian Rouson

unread,
Dec 14, 2016, 4:57:41 PM12/14/16
to
On Tuesday, December 13, 2016 at 11:16:46 PM UTC-8, Hirst, Adam Phillip wrote:
>
> Awesome! Could you maybe give a trivial example of the usage? Also, as
> was asked elsewhere in this thread, are there plans to introduce a flag
> -std=f2015 in the near future?
>

On Tuesday, December 13, 2016 at 11:16:46 PM UTC-8, Hirst, Adam Phillip wrote:
>
> Awesome! Could you maybe give a trivial example of the usage? Also, as
> was asked elsewhere in this thread, are there plans to introduce a flag
> -std=f2015 in the near future?
>

Here's the example that motivated me to advocate for this feature in committee discussions:

module assertions
implicit none
contains
pure subroutine assert(assertion,description)
character(len=*), intent(in) :: description
logical, intent(in) :: assertion
if (.not. assertion) error stop "Assertion '" // description // "' failed"
end subroutine
end module

program main
use assertions, only : assert
implicit none
real :: a=-1.,b
b = f(a)
contains
pure function f(x) result(y)
real, intent(in) :: x
real :: y
call assert(x>0.,"positive x")
y=sqrt(x)
end function
end program

Calling an assertion utility in a pure procedure necessitates that the assertion procedure be pure. If one desires invocation-specific output from the assertion procedure, then having a variable error stop code is the only option because no other I/O is allowed in a pure procedure.

This is a perfect example of why I won't program to the lowest-common-denominator of supported language features. Life is too short. Developer time is valuable. And I have found assertions invaluable time-savers when diagnosing bugs.

Damian

Dick Hendrickson

unread,
Dec 14, 2016, 5:40:27 PM12/14/16
to
10 or so years ago there were a couple of different proposals to add an
ASSERT statement to the language.

ASSERT (lexpr [,string, lots more])

where lexpr had to evaluate to .TRUE. Which operated pretty much like
your example. By making it part of the language there was hope that it
could be embedded in the declarations or above the CONTAINS and a vague
possibility that the optimizer could take a peek at lexpr and use the
information to do better optimizations. In your example the sqrt
function could be replaced by a fast_sqrt that didn't bother with error
checking.

Also, there was the possibility of compiler command line options to
control assertion checking. Once the code was completely debugged ;)
assertion checking would be turned off and the code would run faster.

It died out for a bunch of reasons including difficulity and other
higher priority items.

Dick Hendrickson

michael siehl

unread,
Dec 14, 2016, 6:19:38 PM12/14/16
to
| Here's the example that motivated me to advocate for this feature in committee discussions:

Damian,
thanks for sharing this example. Another F2015 feature I am currently using with gfortran is atomic_add. Makes it easy to increment values atomically and works well (I currently use this feature to increment locally exclusively). FYI, my current main focus is on atomic subroutines (and sync memory) for MPMD-style programming: While the (hardware-related?) limitations of atomics might seem to be paramount (I believe to have understood some of the reasons why they declared atomic subroutines as 'deprecated feature' in Modern Fortran explained), I am already in progress with overcoming some of the main limitations and will share some 'tricks' shortly.

cheers
Michael

FortranFan

unread,
Dec 15, 2016, 12:43:08 AM12/15/16
to
On Wednesday, December 14, 2016 at 4:57:41 PM UTC-5, Damian Rouson wrote:

> ..
>
> Here's the example that motivated me to advocate for this feature in committee discussions:
>
> module assertions
> implicit none
> contains
> pure subroutine assert(assertion,description)
> character(len=*), intent(in) :: description
> logical, intent(in) :: assertion
> if (.not. assertion) error stop "Assertion '" // description // "' failed"
> end subroutine
> end module
>
> ..
>
> This is a perfect example of why I won't program to the lowest-common-denominator of supported language features. Life is too short. Developer time is valuable. ..


@Damian Rouson,

You wrote in a thread on this forum not too long ago, "If more Fortran programmers were writing general-purpose libraries, in which they have no control over X (fill in whatever constraint one has) employed by the end application, I suspect the demand for Y (fill in the desired feature here) would have long since reached whatever threshold of demand is required for inclusion in the language,"

Do you think the stage has now been reached where library-developers won't need to "program to the lowest-common-denominator of supported language features" when they aim for structured exception handling (SEH), some 30 odd years (and counting) after the concept was introduced in other languages?

In the example you give, the f(x) computation would be better presented as a library invocation and it will be most useful if the Fortran standards committee started discussions toward adding to the many block constructs in the language and introducing TRY, CATCH, FINALLY facility and allowing the ability to THROW exceptions in procedures in order to move past the concept of an ERROR STOP:

-- begin pseudo code --
program p
..
contains
..
pure function f(x) result(y)

use some_lib_m, only : some_lib_func

real, intent(in) :: x
real :: y

try ! similar to BLOCK in Fortran 2008

y = some_lib_func(x)

catch ( ec => exception_code, et => exception_text, obj => source_object )
!.. similar to ASSOCIATE from Fortran 2003

!.. some processing of exception information elided
if (..) then
! ok, some catastrophic situation detected, do error stop
error stop obj%name() // "returned an exception" // et // to_string(ec)
else
!.. salvageable, so do some clean up and continue
..
end if

finally !.. similar to BLOCK constuct

! some processing elided

end try

end function
end program
-- end code --

Presently I'm forced to "program to the lowest-common-denominator of supported Fortran language features" in my libraries, via procedure pointers for callback and setter method(s) and multiple procedure calls just to achieve a semblance of SEH that others see as normative in their scientific/technical code developed using C++, C#/VB, Python, etc. According to Wikipedia, "Many computer languages have built-in support for exceptions and exception handling. This includes ActionScript, Ada, BlitzMax, C++, C#, COBOL, D, ECMAScript, Eiffel, Java, ML, Object Pascal (e.g. Delphi, Free Pascal, and the like), PowerBuilder, Objective-C, OCaml, PHP (as of version 5), PL/1, PL/SQL, Prolog, Python, REALbasic, Ruby, Scala, Seed7, Tcl, Visual Prolog and most .NET languages."

Under the circumstances, as a library developer I simply don't have the luxury to issue an ERROR STOP; no one will then consume my 'classes' for the caller executive can be a complex simulation doing many things concurrently with my library just one piece of the puzzle it's trying to solve, or a web browser or part of a web service call, or an application running in a private cloud somewhere remote, whatever.

So it'll be great if the next standard revision were to allow my successors to achieve far better than my crude design at a fraction of the time I had to expend on such matters!

Thanks much for your time and attention,

Damian Rouson

unread,
Dec 15, 2016, 12:52:47 AM12/15/16
to
On Wednesday, December 14, 2016 at 2:40:27 PM UTC-8, Dick Hendrickson wrote:
> 10 or so years ago there were a couple of different proposals to add an
> ASSERT statement to the language.
>
> ASSERT (lexpr [,string, lots more])
>
> where lexpr had to evaluate to .TRUE. Which operated pretty much like
> your example. By making it part of the language there was hope that it
> could be embedded in the declarations or above the CONTAINS and a vague
> possibility that the optimizer could take a peek at lexpr and use the
> information to do better optimizations.

Sounds really cool. Thanks for the additional perspective and insights.
For what it's worth, a longer version of the assertion utility includes data
to be appended to the error message:

module assertions
implicit none
contains
pure subroutine assert(assertion,description,data_)
logical, intent(in) :: assertion
character(len=*), intent(in) :: description
class(*), intent(in) :: data_
character(len=:), allocatable :: output_string
integer, parameter :: max_length=1024
select type(data_)
type is(real)
output_string = repeat(" ",ncopies=max_output_length)
write(string,*) data_
type is(integer)
output_string = char(data_)
class is(object)
output_string = repeat(" ",ncopies=max_output_length)
write(string,*) data_
class default
output_string = "(unrecognized data type)"
end select
if (.not. assertion) error stop "Assertion '" // description // "' failed with data " // data_
end subroutine
end module

where "object" is an abstract type with a deferred generic output binding. The above
code relies upon what my book defines as the Object pattern in which every type in a project extends a universal parent type (named "object" above) which makes the above code work for any type in the project. In such a scenario, the "object" type must define a
generic binding for derived-type output. The Object pattern is named to resemble
languages such as java, in which every class extends a universal parent class named
Object that the language provides.

>
> Also, there was the possibility of compiler command line options to
> control assertion checking. Once the code was completely debugged ;)
> assertion checking would be turned off and the code would run faster.
>

When I want to I turn off assertions, I do so by conditioning the "assert" call on
the value of a compile-time logical constant:

module assertions_module

!...

integer, parameter :: assertions=.false.

!...
end module

program main
use assertions_module, only : assert, assertions
contains
function f(x) result(y)
!...
if (assertions) call assert(x>=0.,"non-negative x")
!...
end function
end program

Then a compiler should be able to eliminate the call from the executable program during the dead-code removal phase of optimization.

Damian


Damian Rouson

unread,
Dec 15, 2016, 1:34:37 AM12/15/16
to
On Wednesday, December 14, 2016 at 9:43:08 PM UTC-8, FortranFan wrote:
> On Wednesday, December 14, 2016 at 4:57:41 PM UTC-5, Damian Rouson wrote:
>
>
> You wrote in a thread on this forum not too long ago, "If more Fortran programmers were writing general-purpose libraries, in which they have no control over X (fill in whatever constraint one has) employed by the end application, I suspect the demand for Y (fill in the desired feature here) would have long since reached whatever threshold of demand is required for inclusion in the language,"

I think X was types used by the calling procedure and Y was generic programming. I'm not sure I would broaden the statement beyond that.

>
> Do you think the stage has now been reached where library-developers won't need to "program to the lowest-common-denominator of supported language features" when they aim for structured exception handling (SEH), some 30 odd years (and counting) after the concept was introduced in other languages?

My experience with generic programming and exception handling is very limited. (I did like
the article that Arjen Markus published on a way to emulate exception-handling using
alternate return in Fortran. Unfortuantely, alternate return will be declared obsolete in
Fortran 2015.) There is clearly demand for both from users and interest in both on the committee. The primary limitation is resources both on the committee and on compiler teams. While the Fortran committee is healthy (with roughly an order of magnitude more active participants than the COBOL committee, which was disbanded because it dropped below the ISO minimum of three members), I believe it remains the case that really big new features such as generic programming and exception-handling would benefit greatly from having increased participation by interested parties. Even given interest in a feature (there
certainly is interest in the above two features on the committee), there has to be a subgroup
that reaches the critical mass to sort out the messy details of integrating such big changes into a 60-year-old language without wreaking havoc or hurting one of the most important
advantages of Fortran: performance.

And then the compiler implementors have to have the resources to implement the feature. In many cases, they just don't have the staffing to keep up.

> According to Wikipedia, "Many computer languages have built-in support for exceptions and exception handling. This includes ActionScript, Ada, BlitzMax, C++, C#, COBOL, D, ECMAScript, Eiffel, Java, ML, Object Pascal (e.g. Delphi, Free Pascal, and the like), PowerBuilder, Objective-C, OCaml, PHP (as of version 5), PL/1, PL/SQL, Prolog, Python, REALbasic, Ruby, Scala, Seed7, Tcl, Visual Prolog and most .NET languages."

The most successful amongst these languages benefit from greater resources either
because of corporate backing or a bigger user community (and bigger standards
committee in the case of C++) and usually both.

More than anything else, I think Fortran suffers from the fact that the world does
science on a shoestring budget (and that problem is only likely to become worse
with 17 U.S. Department of Energy national laboratories employing roughly 100,000
contractors and employees led by a presumptive Secretary of Energy who would
have stated in a national debate that he wanted to eliminate the entire department
if only he could have remembered the name of the department at the time).
Commercial compiler teams are under-staffed. The most widely used open-source
compiler (gfortran) is developed primarily by volunteers, which is not the case for
its sibling compilers (gcc, g++, etc.). Very few organizations contribute financially
or in terms of developer time to gfortran, which contrasts the substantial corporate
contributions to other GCC front ends.

We need people to join the Fortran committee. We need people to contribute
project funds to gfortran developers. We need whole organizations to make
standards-compliance a requirement for major acquisition contracts that involve
hardware that ships with compilers. The year of 2017 is a critical turning point
during which the committee will start to consider new features for the first time
since I started attending roughly 3 years ago. This is the best time to get involved.
Generic programming and exception-handling are massive changes that require
considerable human resources to develop.

Damian

Damian Rouson

unread,
Dec 15, 2016, 10:19:49 AM12/15/16
to
On Wednesday, December 14, 2016 at 9:52:47 PM UTC-8, Damian Rouson wrote:

> output_string = char(data_)

My use of the intrinsic function char() above was incorrect. That line should be
replaced with internal file output jus as in the other select type blocks.

Damian

JB

unread,
Dec 15, 2016, 2:43:18 PM12/15/16
to
On 2016-12-15, FortranFan <pare...@gmail.com> wrote:
> Do you think the stage has now been reached where library-developers won't need to "program to the lowest-common-denominator of supported language features" when they aim for structured exception handling (SEH), some 30 odd years (and counting) after the concept was introduced in other languages?

Isn't SEH some kind of Microsoft-specific implementation of exception handling rather than describing the concept in general?

> Presently I'm forced to "program to the lowest-common-denominator of supported Fortran language features" in my libraries, via procedure pointers for callback and setter method(s) and multiple procedure calls just to achieve a semblance of SEH that others see as normative in their scientific/technical code developed using C++, C#/VB, Python, etc. According to Wikipedia, "Many computer languages have built-in support for exceptions and exception handling. This includes ActionScript, Ada, BlitzMax, C++, C#, COBOL, D, ECMAScript, Eiffel, Java, ML, Object Pascal (e.g. Delphi, Free Pascal, and the like), PowerBuilder, Objective-C, OCaml, PHP (as of version 5), PL/1, PL/SQL, Prolog, Python, REALbasic, Ruby, Scala, Seed7, Tcl, Visual Prolog and most .NET languages."

To be frank, the more I have used exceptions in other languages the
less I like them. Also, they are not as simple as they seem. Take C++,
for instance, where the industry has struggled with exception safety
for a couple of decades. It's not such a problem for many of the
languages in your list above, since they can rely on the GC to clean
up, but well, Fortran doesn't require a GC. And, like C++, Fortran
would have the issue of a lot of existing code written before
exceptions were added to the language. In Fortran, as long as you can
use allocatables you get more-or-less RAII for free, but if you need
pointers, well, you're out of luck more or less then.

Also, that other languages have some form of exceptions, doesn't mean
they're all equivalent. E.g. the eternal flamewar between checked vs.
unchecked exceptions..

Personally, what I like most at the moment is Haskell/Rust style error
handling (you can call it monadic error handling if you want to sound
fancy). To be ergonomic, that I think demands some kind of sum
types/tagged unions/strongly-typed enums/ or whatever you want to call
them (which per se are useful for a lot of other things too, so might
be a useful addition to the language by themselves), and pattern
matching on them. But really, I think that's a smaller change to the
language than bolting on exception handling. See
e.g. https://en.wikipedia.org/wiki/Option_type for some simple
examples.

> Under the circumstances, as a library developer I simply don't have the luxury to issue an ERROR STOP; no one will then consume my 'classes' for the caller executive can be a complex simulation doing many things concurrently with my library just one piece of the puzzle it's trying to solve, or a web browser or part of a web service call, or an application running in a private cloud somewhere remote, whatever.

I think issuing ERROR STOP in library code is Ok, provided you do so optionally. Say something like

subroutine foo(..., errmsg)
...
character(len=*), intent(out), optional :: errmsg
...
if (something_bad_happened) then
if (present(errmsg)) then
errmsg = "Frobnicator position invalid"
else
error stop "Frobnicator position invalid"
end if
end if
end subroutine


That gives the application developer a choice between handling error
conditions (or explicitly ignoring them at his own peril, FWIW), or
just letting the application terminate with an error message.

This is of course quite similar to how many Fortran statements (say,
allocate, read, write) work wrt. an optional stat= specificer (or
iostat=,iomsg= for I/O statements).


--
JB

FortranFan

unread,
Dec 15, 2016, 4:31:10 PM12/15/16
to
On Thursday, December 15, 2016 at 2:43:18 PM UTC-5, JB wrote:

> ..
>
> Isn't SEH some kind of Microsoft-specific implementation of exception handling rather than describing the concept in general?
>


No! The term "Structured Exception Handling" was first introduced back in 1975 by John B. Goodenough as a general programming language concept:
http://dl.acm.org/citation.cfm?doid=512976.512997


> ..
>
> To be frank, the more I have used exceptions in other languages the
> less I like them. Also, they are not as simple as they seem. .. Personally,
> what I like most at the moment is Haskell/Rust style error
> handling (you can call it monadic error handling if you want to sound
> fancy). ..

Around me in industry I find code after code in FORTRAN being replaced with those developed using C++ and C#/Visual Basic even toward scientific/technical applications and which all make a good use of exceptional handling as supported in these languages; nothing stands out in terms of difficulty in usage by scientists and engineers relative to any other feature in these languages. As I mentioned upthread, it's as normative as any other coding pattern involving these languages. And looking at Python and SciPy of late, I see extensive use of its exceptional handling facility even in code used for technical stuff, almost as a flow control construct. This is not "bleeding edge" stuff by any means to be alarmed about.

Thanks for pointing the error handling in Haskell/Rust, I'll check it out.

Damian Rouson

unread,
Dec 16, 2016, 11:53:52 PM12/16/16
to
Feedback on this article's perspective is welcome:

http://www.lighterra.com/papers/exceptionsharmful/

I find it compelling, but it's also more than a decade old so possibly some of what is written has been addressed in the languages that have exception-handling. I am especially interested in perspectives on what the article says about parallel programming. Now that Fortran is an inherently parallel programming language (even the program "print *,'hello, world'; end" can be executed in parallel by compiling it with the appropriate flags), new features need to play nicely in the sandbox with coarrays, DO CONCURRENT, array statements, and ELEMENTAL procedures, all of which are implicitly parallel (or at least explicitly unordered).

Damian

michael siehl

unread,
Dec 18, 2016, 10:03:35 AM12/18/16
to
|Feedback on this article's perspective is welcome:

Just some of my personal thoughts regarding error handling:
Fortran's error return codes are convenient to handle runtime errors but not to handle logic errors. Implementing a customized (serial) error handler (for both, handling of runtime and logical errors) with Fortran object (based) programming should not be that difficult for a programmer: Just create an error handler object with the functionality required and call it's methods in case an error occures. For runtime errors, it may be better to leave many of the possible errors to the the runtime system. Logical errors MUST be handled by the programmer.

A Try-Catch block syntax in the language itself would have one main advantage: The program logic codes within a Try-block would be less interspersed with error handling related codes, and thus the program logic codes could be easier to read.

I am currently struggling with atomic subroutines to further develop a MPMD-style programming to hopefully set up MPMD-style coarray teams (where a team may consist of quite different objects to be executed on the team's coarray images). Within such a parallel scenario I could imagine the use of different kinds of (self-implemented) error handlers: One for use on the worker images (sequential style), another one for each coarray team (possibly executed on it's own coarray image), as well as another error handler to handle the overall errror status of the teams (executed on a coarray image not belonging to a specific team).
This is currently hypothetical because it requires two-sided synchronizations and thus the transfer of a vector (containing two values) with a single atomic_define statement and an array technique (with atomic_define) to prevent that values are getting overwritten by other images.

cheers
Michael

Wolfgang Kilian

unread,
Dec 19, 2016, 11:15:55 AM12/19/16
to
This is indeed a very good summary of the pitfalls. All points as
raised there are valid, I think. Unfortunately, they are as valid, or
even worse, if exceptions are unavailable or avoided. The problems that
the article describes, are inherent problems of algorithms and data
structure.

First of all, in my understanding, exceptions are not primarily a means
of error handling or treating errors in a special way. They are a means
of handling a certain condition in a graceful way - that some algorithm
should not be completed to the very end, so there is need of an
alternate exit. This is a property of many good algorithms, and since
one always needs a workaround -- alternate returns with statement
labels, logical flags, return codes, etc. -- why not use exceptions
directly? As an example, when searching for an object in a data
structure, the exception is raised as soon as the object is found, so
the search should be terminated. This is definitely not an error
condition, but a textbook example for an exception.

The next question is whether one must have special syntax for this. For
subroutines, all functionality of exceptions can be replaced by an extra
argument and a check immediately after return. This has to be done at
every stage in the call sequence. If there was a syntax that makes the
semantics more explicit, it would help the human reader to understand
the program. One would get rid of returns and conditional checks in the
middle of a subroutine and replace them by a more expressive "raise
exception" statement. In the caller, the checked block and exception
handlers would be easily visible as such. Otherwise, nothing special.

For functions, exceptions cannot be so easily be emulated. If a
function raises an exception, its result must not be digested further,
the calculation of an expression where it is embedded must be aborted,
raising the same exception again. I think this can be defined as an
addition to Fortran, but it is more subtle than subroutines. Functional
languages work perfectly with exceptions.

For parallel execution, exceptions are actually an excellent way to deal
with conditions (expected or unexpected) on individual images. I I
think I get the message of the cited paper, but in that context my
conclusion would just be the opposite. One has to think in terms of
languages such as Erlang, where this possibility is expected and built
in ('let it fail'). To make this work, exceptions would have to
cooperate well with coarrays, of course. I don't say it's easy, but I
also don't see a good alternative.

Pitfalls.

- Exceptions can screw up I/O. Yes, but this is no better and no worse
than working with IOSTAT, except that the condition cannot be ignored
anymore when it raises an exception. Handling IOSTAT is easy to forget,
like any other 'error code'. If exceptions in I/O are allowed in the
first place.

- Exceptions degrade performance. Yes, therefore I think that the set
of allowed exceptions should be explicitly declared in a procedure, in
the header. The possibility of exceptions can then be accounted for by
the compiler (explicit interface required).

- Exceptions require cleanup. Again, this is neither better nor worse
than a RETURN in the middle of a procedure. Allocatables and objects
with finalizer will be handled properly. Global state will always pose
a problem, but again this problem is not solved by avoiding exceptions,
it is a problem of the algorithm. (Actually, the language could
restrict exceptions to PURE procedures, then this problem is entirely
absent.)

- Exceptions can be ignored (while return codes are explicit). In this
respect, the article has the logic backwards.

Quote:
Forcing the calling code to handle the error right away is
the correct approach, because it forces the programmer
to think about the possibility of an error occurring.

Exceptions tend to allow, even encourage, programmers
to ignore the possibility of an error, assuming it will be
magically handled by some earlier exception handler.

Sorry, but this is nonsense. An exception that is not supported by the
procedure and handled explicitly (maybe up in the call chain), must
result in program abort. I'd expect a traceback which tells me where it
was raised. It cannot be ignored. By contrast, an error/return code
doesn't force anything, it can be silently dropped.

This article appears to be heavily influenced by experience with C++ and
its descendants, where functions have return codes and most data
structures are explicitly built with pointer hierarchies. Of course,
those are fragile. In Fortran, there are no return codes (unless the
user defines them), and one can avoid pointers entirely or use
finalizers if necessary. And Fortran has PURE, which could restrict the
use of exceptions and solve essentially all of the problems listed.

Fortran coarrays are built-in, there is no explicit communication with a
thread library, so the integration of exceptions can be controlled by
the language itself. All of this would allow a safe implementation like
it exists in various functional languages, where exceptions are actually
an integral part of the language. Apparently, the article assumes a
shared-memory situation where all kinds of collisions can occur.
Fortran's coarrays assume a multi-image setup - any image can handle its
own exceptions. Communicating exceptions might require some new additions.

I think the article completely misses the rationale for exceptions, and
the pitfalls can easily be avoided in a language that is inherently more
safe than C++. It is probably true that they can't be avoided in C++.
I don't see any advantage in the proposed traditional alternative
(numerical codes as poor-man's exceptions), because all problems are
there as well.

If the committee decides to consider exceptions, they should obviously
implement them in a way that exploits the safety measures of the
existing language. Exceptions can't work with legacy code (implit
interfaces etc.). If at all, they should be designed along coarrays
(and DO CONCURRENT, ELEMENTAL etc.).

The main point is whether the subject requires immediate attention. In
my opinion, exceptions as syntax would fill a hole in Fortran as a
modern language since they eliminate the last legitimate use of GOTO (or
any of numerous workarounds) and help the reader understand the purpose
of some particular code. But this might be pure cosmetics.

However, the feature could become extremely valuable if it would
integrate smoothly with Fortran's model of parallel execution (see
Erlang, etc.). This has to be worked out in detail. I don't find any
relevant argument in the quoted article.

-- Wolfgang



--
E-mail: firstnameini...@domain.de
Domain: yahoo

FortranFan

unread,
Dec 22, 2016, 3:06:58 AM12/22/16
to
On Friday, December 16, 2016 at 11:53:52 PM UTC-5, Damian Rouson wrote:

> Feedback on this article's perspective is welcome:
>
> http://www.lighterra.com/papers/exceptionsharmful/
>
> ..

@Damian Rouson,

Thanks for providing the link to what seems more like a blog post with a twist on Djikstra's famous take on the GOTO statement back in 1967.

Here're some comments:

1) The author should at least have made an attempt to publish his thoughts on a wider platform, perhaps a peer-reviewed journal, in order to initiate more informed discussions on the topic.

2) I think the author's views were misplaced even at the time he made the post and are horribly outdated at the present time.

3) His blogpost comes across to me as mostly intellectual diarrhea, quite repetitive, and rather weak in its arguments. His solution to all his stated problems is error return codes which has been too restrictive and unsatifactory in many circumstances. The author also overlooks several issues:

a) vast amounts of programs written, especially in industry, using languages such as FORTRAN (66 to IV to 77 with extensions) with no modern exception handling facility happen to be where the callers simply ignore error return codes.

b) in the few instances where the error codes are processed, the control flow follows "if error, go to xx" approach which has many of the same issues the author bemoans in terms of a decidedly serial path, corrupt state, possibly "out of band", opaque if not "hidden" flow and so forth.

c) the author brings up parallel programming but fails to bring up computer science research dating back decades that sought to integrate exception handling with parallel programming. In addition, the author fails to address any of the underpinnings of parallel programming such as PURE functions that lead to considerable restrictions on error return codes with languages such as Fortran effectively precluding that option altogether.

d) the focus of blogpost appears more toward general-purpose programming and it doesn't address any particular paradigms or approaches or needs of any specific domain such as scientific/technical computing. As such, the author fails to consider generic programming, which can be of great value in scientific and engineering applications. Robust and efficient code using generic programming constructs with compact and expressive syntax in languages that offer strong support for generics also make good use of exception handling features; the use of return codes would be highly out of place here. The same applies to object-oriented programming.

e) program termination is increasingly not an option; much code belong to libraries that need the flexibility to raise valid exceptions in addition to returning error codes.

4) It's difficult to separate the tone of the blogpost from many of the pseudo=scientific denunciations of and fear-mongering toward object-oriented programming, plenty of which can be noticed in cyberspace. I, for one, was long misled by such denouncements of OOP and I needlessly avoided the paradigm for far too long, only to realize the folly of my ways later at considerable cost, regret, and agony.

5) Instead of allowing fear of an abstract nature to deter progress, I suggest those involved with the advancement of Fortran such as the standards committee members think positively and broadly about exception handling, research additional literature and consider ways in which to adapt the exception handling concept with Fortran's rich legacy and strength. Papers and information such as those listed below on parallel programming considerations can possibly be more relevant and useful than the detraction offered by the above blogpost:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0451r0.html

http://link.springer.com/chapter/10.1007/11818502_4

https://www.researchgate.net/publication/300252589_Exception_Handling_with_OpenMP_in_Object-Oriented_Languages

http://dl.acm.org/citation.cfm?id=123058

https://www.cs.ucsb.edu/~ckrintz/papers/zhang-pppj07.pdf

https://msdn.microsoft.com/en-us/library/dd460695(v=vs.110).aspx

As suggested elsewhere, Fortran can learn from other implementations and avoid some of the pitfalls to include safer and explicit syntax and solutions for exception handling, as was achieved with other concepts (e.g., Fortran POINTERS which are more like aliases). Focus on PURE functions may be a good place to start.

Thank you for your attention,

Wolfgang Kilian

unread,
Dec 22, 2016, 7:06:01 AM12/22/16
to
I wouldn't bash the author for that article - everything written there
might be entirely correct regarding C++. I can understand that in a
language where data pointers, global state, hardware/driver interaction,
manual memory management are the norm, a reasonable implementation of
exceptions is impossible. A couple of years ago there was a thread in
this newsgroup where it was stated that the specification of exceptions
in the C++ standard itself is faulty, ambiguous and unsafe - by a former
member of the C++ standard committee, if I remember correctly. Also,
for other languages which follow similar concepts as C++, the statements
could be as valid.

(Modern) Fortran is a more high-level language by concept, and if this
fact is exploited, I can imagine a specification of exceptions as a
language feature that doesn't suffer from such problems. In particular,
low-level concepts such as EQUIVALENCE, implicit interfaces, etc., have
to be explicitly excluded from interacting with exceptions. Pointers
will be a source of problems which have to be sorted out, among other
issues.

Nevertheless, this discussion doesn't add anything about the relevance
of exceptions - namely, to which extent they would solve problems that
cannot be solved in the present language in a satisfactory way. I think
there are some - in relation to parallel programming - but this deserves
detailed study.

FortranFan

unread,
Dec 22, 2016, 12:15:24 PM12/22/16
to
On Thursday, December 22, 2016 at 7:06:01 AM UTC-5, Wolfgang Kilian wrote:


> ..
>
> I wouldn't bash the author for that article - everything written there
> might be entirely correct regarding C++. ..


I disagree entirely. It's possible there were issues and inconsistencies with certain C++ flavors prior to the 1998 standardization, however the exception handling facility has been strengthened and extended considerably with each revision since and I think what is offered in C++ 11 and C++ 14 and what is being proposed for C++ 17 along with the concept of future-proofing for parallel algorithms appear quite sound, modern, and effective. Talking to 2 fairly big vendors who have moved to C++ from FORTRAN over the last decade or so for their large libraries serving their big process simulation software, they don't see any major concerns with the language standard, their challenges are simply to make best utilization of existing facilities and to get their programmers to follow some discipline; but they had even larger issues with their FORTRAN code, it was unfathomably ugly to say the least.

No one is saying exception handling should be added to Fortran willy-nilly or to copy-and-paste blindly from some other language, whatever it be.

The issue I have is the categorical statement by the author of the blogpost, ".. all programming language designers should just say no to exceptions .." and the entire theme that goes along with it. It's up to a language whether to offer a full-featured, flexible, and structured approach (try.. catch.. finally, throw, extensible/custom exception classes, etc.) or a 'diplomatic' one such as the monadic exceptions of Haskell; Fortran may choose to begin with some limited extensions to its IO facility and some capability for PURE procedures which is after all one of the main aspects of this thread. Such a limited approach may be acceptable - I don't know, just saying it may be a way to get the process started.

But to simply say no to exceptions and to leave it up to developers to implement some home-grown approaches starting at the low level is being disrespectful of the practitioners, in this day and age I feel. Especially considering widespread evidence of reasonable and safe use with so many other languages. Developer time is so valuable, as mentioned by Damian Rouson.

Ian Harvey

unread,
Dec 22, 2016, 2:24:27 PM12/22/16
to
On 2016-12-23 04:15, FortranFan wrote:
> ...Fortran may choose to begin with some limited
> extensions to its IO facility and some capability for PURE procedures
> which is after all one of the main aspects of this thread. Such a
> limited approach may be acceptable - I don't know, just saying it may
> be a way to get the process started.

The restrictions associated with PURE enable a relatively deterministic
outcome from sections of code that may be executed in an unspecified
order. I don't think exceptions are compatible with that - if the
language had exception I think the restrictions on PURE would have to be
expanded to prevent exceptions from escaping PURE procedures.

For example, consider operations being executed in an unspecified order
on the elements of an array. If an operation on one element fails an
issues an exception, what's the status of the other elements?

Damian Rouson

unread,
Dec 22, 2016, 7:43:56 PM12/22/16
to
On Thursday, December 22, 2016 at 12:06:58 AM UTC-8, FortranFan wrote:
> On Friday, December 16, 2016 at 11:53:52 PM UTC-5, Damian Rouson wrote:
>
> > Feedback on this article's perspective is welcome:
> >
> > http://www.lighterra.com/papers/exceptionsharmful/
> >
> > ..
>

@FortranFAn

Thanks for the comments and links. I'm guessing it will take me quite some time to review the points and references so they are much appreciated even if I don't respond in a timely manner.

I hope you and others will consider joining the committee. Most members have employers with specific needs and limited resources. The more people there are involved, the more likely it is there will be manpower to craft ambitious new features that potentially intersect with a broad cross-section of the language. The fewer people involved, the stronger is the argument for incrementalism. As mentioned previously, 2017 is a critical time for participation for anyone interested in proposing new features.

Damian

Damian

Damiam

Adam Hirst

unread,
May 10, 2017, 7:23:25 AM5/10/17
to
I have feedback and an additional query regarding the scenario I
introduced in my opening message to this thread, but first I'd like to
provide a brief summary, so that people don't need to read the entire
backlog in order to follow along. Firstly I'll restate my opening
scenario, and secondly I'll the fruitful discussion which followed.

Once done, I will reply to *this* message with my continuations.


---

1. Opening Scenario

I had modified a library to use ERROR STOP statements instead of just
STOP, so that some routines could be declared PURE, and compiled
according to the F2015 standard. The question was of a meta-standard
nature: if linked to from / called by a program compiled according to an
older standard, do these routines still count as PURE?

There wasn't really a firm answer to this, but this was initially
overshadowed by questions I had about the building/linking process for
libraries and modules-as-libraries/DLLs, resulting in advice from many
here, and closing with comments from FortranFan about .def files.

(Unstated) In the aftermath, I decided against refactoring the library
for license reasons (jburkardt's PPPACK is under the LGPL, static
linking to modified versions is thus not permitted unless the
modifications were LGPL-published, and I was requested to avoid having
to do this, at least during my involvement on my then-current project).


2. Further Discussion

Primarily on assertions, exceptions, whether or not they should be in
the standard, and ways of implementing something similar given current
functionality. Also discussed was the utility of introducing a -f2015
flag into gfortran, which if I understand correctly is on its way.

Particularly noteworthy in my opinion were messages by:

* Wolfgang Kilian (19.12.2016, 17:15 GMT+1)
* FortranFan (22.12.16, 09:06 GMT+1)

on the pros and cons of exceptions, the latter of which was a response
to the article "Exceptions Harmful" posted by Damian.


---

Fortsetzung folgt...

Regards,
Adam


P.S. For anyone whose client does not retain messages older than a
certain date, or past a certain count, the conversation occurred between
13.12.2016 and 23.12.2016, and as of today (10.05.2017) started about
2000 messages ago.

Adam Hirst

unread,
May 10, 2017, 7:56:27 AM5/10/17
to
On 10/05/17 13:23, Adam Hirst wrote:
> I have feedback and an additional query regarding the scenario I
> introduced in my opening message to this thread, but first I'd like to
> provide a brief summary, so that people don't need to read the entire
> backlog in order to follow along. Firstly I'll restate my opening
> scenario, and secondly I'll the fruitful discussion which followed.
>
> Once done, I will reply to *this* message with my continuations.
>
> ----
> SNIP
> ----
>
> P.S. For anyone whose client does not retain messages older than a
> certain date, or past a certain count, the conversation occurred between
> 13.12.2016 and 23.12.2016, and as of today (10.05.2017) started about
> 2000 messages ago.

1. .def Files

FortranFan suggested (in his email of 13.12.2016, 17:30 GMT+1) to use
.def files as part of a build process, to make it possible to easily
link to entities in a Fortran Library which is to be compiled separately
from the calling program, and demonstrated how this should be possible
using Code::Blocks (which I use and originally mentioned).

I wanted to clarify whether or not such .def files should be generated
*by* C::B during the build process, or whether they must necessarily be
specified by myself? When building a test module library project,
regardless of whether the "Create an Import Library" checkbox is ticked,
no .def files appear to ever be created.

a) The sample .def file shown in that same message appeared to only
reference the module, and not any of its contained subroutines (or
types, though there are none there) - is this then automatically handled
by the .mod file, or would that also need to specified?

b) Is all this .def file stuff only useful for Windows or
interoperability with MSVC? I'm currently now developing primarily on
GNU/Linux, and there are presently no requirements for building/running
on Windows machines.

c) Does this additional constraint of having to compile/link against
.mod files interact with the LGPL? And/or: do .mod files need to be
distributed along with the main executable and DLL/so files in order to
run, or are they solely for linking?

My impression is that none of this is able to sidestep the fact that one
still needs the .mod files (from the right compiler version), and to
link against those, in order to be able to link against a Fortran
"Module Library" and use its encapsulated routines or derived types.


2. Parallelism

a) If one is successfully linking to PURE subroutines from modules
"in" an external library (presumably with the assistance of the .mod
files, see above), are these "external" calls still regarded as
thread-safe; and if so, to what extent can this then be parallelised
(either automatically by GCC, or manually).

[Hopefully this doesn't necessitate us discussing stuff like OpenMP -
just a comment on whether or not such parallelism tools can behave when
calling external routines would be nice]

b) Alternatively: if one is linking generally to routines from an
external library and promising (in the INTERFACE block) that those
routines are PURE, putting the glaring standards non-compliance aside,
how are GCC/OpenMP/whatever likely to treat this?

[More in terms of what assumptions they'll make and what they'll attempt
to do, rather than what will actually happen.]

---

I'm trying to organise my understanding on this, to decide whether, at
what point, and how to try to get my own code utilising more than one
thread, as huge parts of my algorithm are, at least in principle,
independent from each other. (Most of my quantities to be evaluated
involve aggregating arrays of intermediate values determined in what
could easily be DO CONCURRENT blocks - if the library calls were PURE.)


Very best of regards,
Adam

Anton Shterenlikht

unread,
May 10, 2017, 9:52:18 AM5/10/17
to
Adam Hirst <ahi...@cedint.upm.es> writes:

>I had modified a library to use ERROR STOP statements instead of just
>STOP, so that some routines could be declared PURE, and compiled
>according to the F2015 standard. The question was of a meta-standard
>nature: if linked to from / called by a program compiled according to an
>older standard, do these routines still count as PURE?

My short answer is "yes, but don't do it".

While using code compiled to an older standard
in a program compiled to a newer standard is a daily
practice, e.g. using f77 blas/lapack libraries in f2008 programs,
doing it the other way round might lead to problems.

In this particular case there is no obvious harm,
because we are talking about error termination.
The main program can use the fact that your
routine is pure and call it from e.g. a
do concurrent loop. Even though according
to the f2008 logic a pure routine inside
a do concurrent must not bomb, in case your
error stop is triggered, it does bomb, but nobody
cares about this violation because you specifically
want a catastrophic exit, without any care
of the program data.

But there might be cases (I cannot think of one now)
when calling a routine compiled to a later standard
from a program compiled to an older standard will
have unexpected results, likely in cases where
the argument association rules have changed between
those standards.

Anton

Anton Shterenlikht

unread,
May 10, 2017, 10:08:41 AM5/10/17
to
Adam Hirst <ahi...@cedint.upm.es> writes:

> a) If one is successfully linking to PURE subroutines from modules
>"in" an external library (presumably with the assistance of the .mod
>files, see above), are these "external" calls still regarded as
>thread-safe; and if so, to what extent can this then be parallelised
>(either automatically by GCC, or manually).
>
>[Hopefully this doesn't necessitate us discussing stuff like OpenMP -
>just a comment on whether or not such parallelism tools can behave when
>calling external routines would be nice]

You mean something like this:

module m
contains
pure subroutine s
error stop
end subroutine s
end module m

program p
use m
do concurrent (i=1:10)
call s
end do
end program p

Where the module is in a separate file
and compiled with f2015, and the program is
compiled with f2008?

I don't see a problem.
You tell the processor that your routine is pure
("thread" is not used in the Fortran standard),
so it will treat it as pure.

> b) Alternatively: if one is linking generally to routines from an
>external library and promising (in the INTERFACE block) that those
>routines are PURE, putting the glaring standards non-compliance aside,
>how are GCC/OpenMP/whatever likely to treat this?

I don't see a problem.
If you tell the compiler it's pure
and the compiler cannot see that it
is not pure, it will treat it as pure,
with all usual possibilities for parallelisation.

If in fact, you managed to fool the compiler
to pass a non-pure routine as pure,
then you deserve all you get.
However, again, in the error stop case,
I cannot see any obvious harm.

I'm happy to be corrected if I'm missing something.

Anton

FortranFan

unread,
May 10, 2017, 10:49:11 AM5/10/17
to
On Wednesday, May 10, 2017 at 7:56:27 AM UTC-4, Adam Hirst wrote:

> ..
>
> 1. .def Files
>
> FortranFan suggested (in his email of 13.12.2016, 17:30 GMT+1) to use
> .def files as part of a build process..
>
> I wanted to clarify whether or not such .def files should be generated
> *by* C::B during the build process, or whether they must necessarily be
> specified by myself? When building a test module library project,
> regardless of whether the "Create an Import Library" checkbox is ticked,
> no .def files appear to ever be created.
> ..

> b) Is all this .def file stuff only useful for Windows or
> interoperability with MSVC? I'm currently now developing primarily on
> GNU/Linux, and there are presently no requirements for building/running
> on Windows machines.
>

Note all the information about .def files is specific to Windows. If you're on GNU/Linux and working with shared libraries (.so), there may be separate considerations which I know nothing of. But you can *ignore* all the Windows-specific stuff if you are working exclusively on GNU/Linux.


..
>
> My impression is that none of this is able to sidestep the fact that one
> still needs the .mod files (from the right compiler version), and to
> link against those, in order to be able to link against a Fortran
> "Module Library" and use its encapsulated routines or derived types.
>

Yes, that's right. .mod files are integrally related to Fortran and the use of MODULEs and there is no getting away from it if the calling program(s) are in Fortran and they have USE statements against the stuff from the Fortran libraries. But if the callers are in C/C++, then the callers will NOT need the .mod files of course because the Fortran procedures will get invoked via some interoperability layer (e.g., BIND(C) in the Fortran standard) which will be .o files instead of .mod.

Now note the stuff below is only of relevance to those interested in Windows: OP wrote

> a) The sample .def file shown in that same message appeared to only
> reference the module, and not any of its contained subroutines (or
> types, though there are none there) - is this then automatically handled
> by the .mod file, or would that also need to specified?
>

My work process is to *always* create the .def files *myself*, giving close attention to what all procedures (FOO in the example upthread whose 'decorated'/'mangled' name happens to be __libfoo_MOD_foo) need to be exported from a library i.e., only exporting those that are needed - conceptually similar to what I would mark as PUBLIC in a Fortran MODULE; note though this is only a loose consideration since linking to build DLLs on Windows have nothing to do Fortran. And once the ordinal numbers are specified (e.g., @1 for __libfoo_MOD_foo in the example), just in some sequential order initially, then I stick with it - this is important for compatibility with programs on Windows that dynamically link against said DLLs. As I mentioned upthread, these are all Windows-specific details and if Windows OS is important enough, I suggest going through the MSDN links I provided. Note at the DLL building stage, a Fortran procedure is no different than a C function so whatever Microsoft would explain in terms of C/C++ functions will hold for Fortran too.

Also, note approach to go about this is inline directives in code with the DLLEXPORT attribute; you can look this up too at the MSDN site. I avoid this such directives due to compatibility issues that can arise once a DLL achieves any kind of broad usage when the calling programs have entirely different cycles of update compared to the DLL. Another factor for me is also to prevent code clutter; I personally tend to use directives as a last resort.


>
> 2. Parallelism
>
> a) If one is successfully linking to PURE subroutines
> ..

A quick comment: my experience at present is the use of dynamically linked libraries, as in DLLs and .so on GNU/Linux, seem to somehow go against the single program (SP) narrative and there is some price to be paid for this. PURE procedures in dynamically linked libraries allow Fortran code with constructs that require PUREity in calling programs to compile Ok (e.g., PURE calling procedures or DO CONCURRENT loops, etc.), that they uphold the necessary conditions for thread-safety (but possibly not the sufficient ones for which things can get rather complicated with OS, processor, and hardware aspects), that they might provide some limited benefits (vectorization, etc.), and that they lay the foundation for a possible great future. But they may not lead to truly parallel execution with immediate performance improvements; in fact, performance may even go the other way relative to ordinary (serial) execution, at least on Windows. For that one may need to resort back to linking calling programs against static libraries e.g., .a on GNU/Linux so that all the object code, symbol tables, everything is all part of the caller, no run-time object loading with library data management then comes into play to hurt parallelism.

Wolfgang Kilian

unread,
May 10, 2017, 12:22:08 PM5/10/17
to
On 10.05.2017 13:56, Adam Hirst wrote:
> On 10/05/17 13:23, Adam Hirst wrote:
>> I have feedback and an additional query regarding the scenario I
>> introduced in my opening message to this thread, but first I'd like to
>> provide a brief summary, so that people don't need to read the entire
>> backlog in order to follow along. Firstly I'll restate my opening
>> scenario, and secondly I'll the fruitful discussion which followed.
>>
>> Once done, I will reply to *this* message with my continuations.
>>
>> ----
>> SNIP
>> ----
>>
>> P.S. For anyone whose client does not retain messages older than a
>> certain date, or past a certain count, the conversation occurred between
>> 13.12.2016 and 23.12.2016, and as of today (10.05.2017) started about
>> 2000 messages ago.
>

> c) Does this additional constraint of having to compile/link against
> .mod files interact with the LGPL? And/or: do .mod files need to be
> distributed along with the main executable and DLL/so files in order to
> run, or are they solely for linking?
>
> My impression is that none of this is able to sidestep the fact that one
> still needs the .mod files (from the right compiler version), and to
> link against those, in order to be able to link against a Fortran
> "Module Library" and use its encapsulated routines or derived types.

.mod files are Fortran's analog of C/C++ include files. They contain
the declarations that a compiler needs in order to be able to use the
types and call the procedures/methods that a library provides.
Compiling against a library requires access to those files.

The only difference is that Fortran's .mod files are generated
automatically, while include files are hand-written (or by some smart
IDE). The downside is that the hand-written files have a portable
format -- they are nothing but source code -- while the generated files
use a vendor-specific format.

Things begin to be tricky when you use a module that uses another
module. Some compilers resolve .mod files recursively (NAG), so all
have to be in the search path. Some compilers repeat all module
information in the next level of .mod files (gfortran), so you need to
access only the top level. The downside is that gfortran's .mod file
parser can take an eternity to finish reading such a top-level .mod file
if there is a complex hierarchy.

The *linking* step doesn't access .mod files. The linker doesn't even
know what .mod files are.

-- Wolfgang
>

0 new messages