Exceptions proposal

So it can appear in an expression?

I’d guess this would address a lot of use cases. My main question would be, how would one “catch” an error stop in a way that doesn’t at least resemble exceptions?

That’s kind of the point. There is no one right answer. It’s application dependent. Calling a different root finding method would likely be an option in some applications.

I agree, but just because a library writer decided to punt (i.e. error stop) in a tricky situation doesn’t mean my application should come crashing down. There may be other options.

As with many things in software development, I think it depends. Which is more complex?

subroutine A(...)
  ...
  call B(..., stat)
  if (stat /= 0) then
    ! do something about it
  end if
  ...
end subroutine

subroutine B(..., stat)
   ... ! no errors possible here
   call C(..., stat) ! errors might occur in here
   if (stat == 0) then
      ! a few more things to do
   end if
end subroutine

subroutine C(..., stat)
   ...
    if (something) then
       stat = SOME_ERROR_CODE
       return
    end if
   ...
end subroutine

or

subroutine A(...)
  ...
  call B(...)
  ...
  catch (SOME_ERROR)
    ! Do something about it
  end catch
end subroutine

subroutine B(...)
   ... ! no errors possible here
   call C(...) ! errors might occur in here
   ! a few more things to do
end subroutine

subroutine C(...)
   ...
   if (something) raise SOME_ERROR
   ...
end subroutine

It seems to me the exception mechanism reduced the line count and avoided some complexity in subroutine B. I’ll admit it’s a bit of a hand-wavy, contrived example, but it’s not impossible to imagine some real code that could resemble the pattern.

This is a perfect example. The time-stepping loop is probably not calling the newton’s method procedure directly. So an exception mechanism would alleviate having the whole call-stack between them littered with stat arguments and if blocks.

Maybe if we didn’t call them exceptions? How about, indirect errors?

1 Like

Look, Fortran can serve up a certain level of functional programming paradigm, but it has limits and limitations. To be able to consume a root-finding function in Fortran expressions in any reliable manner in real code is effectively beyond reach; try.. catch.. type exception handling will barely move the needle on this, it’s unfortunate but that’s reality - “everything functional” is an aspiration that is a bridge too far in Fortran!

One possible option is a “registration mechanism” that a program main, whether initiated by means of a Fortran processor or a companion C processor, can invoke which specifies a handler, a subprogram with certain defined interface, that can complete certain actions toward program continuation or error termination. Fortran has had a semblance of this with defined IO and with defined finalization of finalizable types.

That might be a good reason, but to be useful, the function needs to be bulletproof. It needs to always converge, with a small error, and with no domain limits or anything like that that might need to be reported back. You can report back a few error situations with IEEE exceptional values, but that’s only for floating point functions. Character functions can sometimes report back error strings through their return values. Otherwise, it should probably be a subroutine, with optional error return arguments or derived type arguments and so on. Another issue with functions in these cases is that they often cause problems if/when write statements are activated internally, both when they occur in-line in expressions, or worse, when the function reference itself is part of an i/o list. In that last case, your program can just appear to hang due to the restriction on recursive i/o to the same output unit.

One thing I’ve been doing more often lately is to define a derived type that returns error codes, sometimes several of them to differentiate all of the possible error cases, and maybe also an allocatable string that can be set appropriately. The allocatable string is nice because it doesn’t occupy much space unless it is actually used, and then its length isn’t limited when it is used. If the argument is optional, then the program can error stop internally if it isn’t present, and, if it is present, then it can return gracefully to the caller with hopefully some useful information about what when wrong and what to try next. However, the bad thing about this approach is that each function might need its own derived type, so a program unit might need several of these things, and it seems difficult to pass them back more than one level in the call stack. So for these reasons, I’m curious how these exceptions proposals might come into play to handle these program situations in a better way.

I totally understand there will be some limitations in Fortran related to functional programming. That’s fine. But I’m not entirely convinced this has to be one of them.

That’s kind of an interesting idea. One would also need a mechanism for “unregistering” such a handler as well. I.e.

register my_handler
call something_error_prone
unregister
! I wouldn't know what to do if an error stop happened down here

:thinking: that kind of looks like a try/catch block that can only handle a single kind of exception.

Actually what this will be is more like the IEEE Exceptions feature already included in the standard since Fortran 2003 e.g., with IEEE_SET_HALTING_MODE that can optionally set the halting to true or false. Registering and unregistering can thus be optional and they pretty much are intended to guide the processor at a higher level in terms of the actions to complete as part of error termination.

Working something like this out first will be an useful second step for the standard and perhaps it’s something which can be tackled in Fortran 202Y. Here I consider the IEEE facilities as the important first step.

What I would prefer is a simple mechanism, that helps me in propagating an error condition upwards, basically by replacing a bunch of if (stat /= 0) return statements. And additionally, it should help me to enforce robust programming by making the error handling on the callers side mandatory (by either declaring that the error can be propagated further up or handling/catching it locally).

I don’t see, why it should add any big burden or run-time penalty for codes using it, if the error condition is an allocatable derived type containing an error code and maybe an optional error message. Being just an additional hidden allocatable, intent(out) dummy argument error, the code raising it would be equivalent to:

  ! raise error_type(code, msg)
  error = error_type(code, msg)   ! LHS is allocated with structure constructor
  return

On the caller side, if the error is not handled but propagated further up, it would be equivalent to

  call some_routine_which_throws_error(..., error)
  if (allocated(error)) return

And if the error is handled on the caller side, it would be equivalent to


  if (allocated(error)) then
    ! some statements handling the error

In the case of functions within expressions, it would be somewhat more complicated, but similar in the spirit.

For sure, in cases, where even an allocation is too much of an overhead, one can still use a simple integer as flag instead. And whenever it is possible to make robust routines carrying out their job without the need for an extra error signaling mechanism, one should certainly do so.

What I wish for is not much more than syntactic sugar, but would make my code (as demonstrated by @everythingfunctional above) more concise. I also do not expect much more from it. It does not have to deal with coarray-parallel issues, it is the callers responsibility IMO to synchronize the error handling and/or make sure that errors are raised/propagated upwards in a synchronized matter.

Note, that registering a callback function which is called at ERROR STOP is only limited use for library authors. (It gives the caller the possibility to make some finalization before everything is stopped / crashes, for sure, but maybe the caller wished to continue running nevertheless…)

There had been several demonstrations, that you can program something similar in pure Fortran already, as listed by @ivanpribec Fortran error handling including stacktrace generation - #2 by ivanpribec
But all of those solutions suffer from unnecessary verbosity due to boiler plate code. Having a concise syntax and the boiler plate being inserted by the compiler would be probably enough for many of us.

3 Likes

@aradi , this is along the lines of a proposal I am working on. The difference would be that the user code would not be responsible for checking the status of the call - the compiled code would do that automatically. (The caller could tell the runtime system how it wants things handled.)

I have some issues I need to work out in my head before writing things down. It would not solve everyone’s scenarios but is closer to the model Fortran already has with the IEEE exception stuff and limits code clutter while posing no overhead to code that doesn’t use the feature.

3 Likes

Please review again the ground reality with Fortran committee work and the views and opinions of majority of the voting members and keep the context in mind.

As things stand currently, nothing really is on the anvil for Fortran 202Y with “exceptions” - just as with Fortran 2023, it is likely to be deferred to a later date.

The suggestion I make re: ERROR STOP is in the context of working with FUNCTION subprograms in Fortran in light of what has transpired during the J3 Fortran committee meeting last week and also other recent developments generally in computing. It then makes sense to start small again with Fortran and thus my suggestion to work something out with Fortran FUNCTIONs. It’s a possible baby step to take with Fortran 202Y.

Re: “maybe the caller wished to continue running nevertheless,” well, KISS with SUBROUTINEs then. Considering the massive constraints with Fortran ecosystem and very limited resources, especially with language development and committee resources and also compiler implementations and developer tools, the use of SUBROUTINEs cannot be beat, practitioners simply have to eschew functional programming style - the find_root example as a function subprogram upthread - with the hope of consuming it in expressions - is simply out of reach in any practical situations, forget about it in Fortran anytime soon. Such a subprogram will have to be a SUBROUTINE for a long way ahead.

But now, FUNCTIONs do have a place in Fortran code, limited nonetheless for certain specific needs. And such FUNCTIONs may be nearly fault-proof but nothing can be 100% So then for the few exceptional situations one may have to do ERROR STOP. It is this circumstance, it is an exception. that will be good to focus. Right now, there is nothing a Fortran program or one initiated by means other than a Fortran processor can do: it is left entirely up to the Fortran processor. Hence with this ERROR STOP problem in FUNCTIONs, there is nothing much the community can work out by themselves, the practitioners need the help of compiler implementors here, and therefore going to the committee on this makes sense.

Coming back to subroutine subprograms though, again the above context with the very poor resource situation for Fortran leads to this: avoid employing ERROR STOP in SUBROUTINEs for the foreseeable future.

With Fortran SUBROUTINEs, the language standard already includes a reasonable degree of facilities to work out error handling via arguments. The practitioners can thus roll their own as they have been doing it since FORTRAN I, or should some common design and error handling patterns - say around a derived type (“class”) - be of interest, then work as much of it out as viable in Fortran stdlib first. Once such an effort is completed, one can come to the committee with some concrete proposal, perhaps around an intrinsic derived type consumable via ISO_FORTRAN_ENV (a la type(c_ptr) from ISO_C_BINDING).

With this last option above, seriously the last thing you want is some few members on the standard committee, who rarely code-in-anger, to offer up some half-baked option that is going to be of very limited use in actual practice but which then leads to the same members from going around and making presentations publicly the Fortran standard 202Y has introduced this “great” feature for error handling when in reality its value won’t even be worth the electricity needed to power the presentation. The named constants of REAL32, REAL64, REAL128, etc. from ISO_FORTRAN_ENV introduced in Fortran 2008 or the ENUMERATION TYPE in Fortran 2023 are but examples of what is offered up that falls far below what a language should have designed when it did so i.e., decades after the concepts had been worked out. There is real risk of such a thing happening with error handling, meaning what comes out ultimately from the “sausage factory” will be so diluted, any caring Fortran practitioner must truly wonder whether it was worth adding something officially to the standard when the community could have crowd-sourced some effort, say in stdlib, that could have produced infinitely better results.

So again, think Fortran stdlib and a lot of community attention on it first, especially if the use cases indicate what you “wish for is not much more than syntactic sugar, but would make my code … more concise. I also do not expect much more from it. It does not have to deal with coarray-parallel issues, it is the callers responsibility IMO to synchronize the error handling and/or make sure that errors are raised/propagated upwards in a synchronized matter”.

Avoid the J3 committee under such circumstances, like the plague please. I will elaborate on this more at a future date, but a practitioner can get the drift of it in this paper from last week’s meeting, “All proposals should be considered to start with minus 100 points. Even if an individual item seems small, there is an issue with language bloat (just look how long it is taking gfortran/flang/some-other-compilers to implement even F2003!). Cost-benefit analysis is thus essential.” This line of thinking which passes unchallenged is at the root of the dilution that leads to half-baked or barely usable solutions in the official language standard.

Readers would do well to pay attention to the quote characters in my comment above, they implying quoting someone else.

The blurb, “look how long it is taking gfortran/flang/some-other-compilers to implement even F2003!),” is not meant by me to offend anyone here. It’s a quote from this paper (https://j3-fortran.org/doc/year/23/23-147.txt) passed by voting members at the last J3 meeting without any of them raising any objections. Readers can look up the link on the author details. I did not quote it in support; to me the whole paper is deeply objectionable to its very core. To me, that paper signifies something that is, to borrow from the Great Bard, deeply rotten in the state of Fortran.

Every one must ask of themselves, “For whom Fortran, for what?”

First and foremost, Fortran must be for its practitioners.

Secondly, it’s for the practitioners to decide for what shall be Fortran.

Then note, among a myriad of other issues, a deeply rotten problem is how things are functioning in the ISO IEC and INCITS organization. The functioning is definitely not placing the practitioners in the front and center of everything around Fortran. The poor, persevering practitioners are almost an afterthought.

There is not enough oxygen and time to laugh at the code of conduct guidelines of above organizations,. This is because the amount of disrespect for the practitioners and all their needs is unbelievable.

Consider the filtering that takes place before a proposal for a Fortran feature comes to the attention of a committee under INCITS for some work. Most Fortranners suffer anonymously at their keyboard and simply think whatever the situation is how it shall remain. A small fraction of them notice a suggestion at a relatively recent GitHub site and they may like a proposal. But an even smaller fraction of them open an account at GitHub and click on the upvote button.

Now, among the upvoted items, a small list catches the attention of a few influential community leads like @milancurcic, who has devoted a ton of time to computational science and developed deep expertise in many aspects and gained great insight on many matters and displayed positive discrimination in selecting only certain ideas that are worthwhile in their judgement. They then direct only a few items that appear worthwhile to them for further work.

Then a WG5 convenor further filters down items by allowing each contributor such as Fortran-lang or @milancurcic or Dancing Bear etc to limit it to 5 items only. Many do not send any.

Out of all this lengthy weeding out process, comes an item - default values of optional arguments - to the subgroup for consideration toward Fortran 202Y.

And what is the feedback as written in the above paper, that it is:

not terribly useful and that its uses will be rare.

Oh my! The sheer arrogance and supremacist mindset of some on the committee is mind-blowing. The utter lack of any humility and respect toward the needs of actual Fortran practitioners, whose coding experiences might become more fruitful and fulfilling and productive when the option to specify default values of optional arguments were to be introduced starting Fortran 202Y, is unfathomable. Now, if the situation were isolated to some specific features or semantics on property enunciated technical reasons, then ok. But no, the problem is deeply systemic and that’s the issue.

But now why is any of this relevant at all to this thread?

Because the suggestions by some readers like @aradi et al. is steering in the direction of “some syntactic sugar” and a bit of ease when it comes to error handling. But the lines in which it’s being contemplated will mostly only be usable when error stop is not in the mix, that is, with subroutines. The suggestions also hint at a possible intrinsic derived type hosted in an intrinsic module (say iso_fortran_env) that may help enable some semantics, perhaps via optional arguments.

Now, the chances are high the Fortran community can achieve most of such ideas via community efforts, e.g., in stdlib.

On the other hand, you can try sending it to the subgroup under INCITS for Fortran 202Y and I can guarantee you that when it comes to actual and official standardization, your proposals will sublimate faster than dry ice on a hot summer day!

The above objectionable paper also effectively defers (which is another, more pernicious form of dismissal) any proposal around a simple-to-standardize string type - a la an intrinsic derived type in Fortran, something that can meet so much of the practitioner use cases to help them overcome the limitations with working with CHARACTER intrinsic type. But any such suggestion dies after running into an immovable object in the form of the author of that paper whose books, by the way, many of you consume.

If something like a string type that among other things will allow jagged arrays of character strings is so difficult due to non-technical reasons to standardize in Fortran (the technical details of such a type have been worked out for 3 decades or more), then you can bet you are not going to get something standardized for an error handling type. And note this: the more you try to simplify it, even less you will get.

If you doubt this, just look at the “enumeration type” in Fortran 2023, it’s deeply flawed. The above same paper now seeks to address one the flaws in Fortran 202Y when that very flaw was pointed out repeatedly to that author back in 2018 and yet it was deliberately overlooked; the author simply dismissed feedback, acted as if all-knowing, worked alone, and produced the flawed product. And now Fortran 202Y has a possible work item to fix that flaw. Do it right the first time requires tremendous humility, it’s clearly unknown to these chairs; the hubris is indescribable. But think about all the time that is wasted and which will have been elapsed for the practitioners.

A surefire bet is an error handling system, no matter how simplified, will suffer a worse fate than the trivially easy enumeration type in the hands of the INCITS committee. And the worst part is the two are inter-related: study almost any of the development documents toward error handling in other programming languages and you will notice they are facilitated by good features toward ENUMs which after all are just a set of named constants and that’s what you use to manage the error codes and exception scenarios.

TL;DR: the Fortran Community should strive to work things out as much as possible among themselves including feature development such as via stdlib and LFortran and seek the help of visionaries such as @certik. Under INCITS and ISO, the “system” wants to do the very least for you as a practitioner. Think outside the box and become as independent as possible from such mere bureaucracies. Otherwise what you will get will always be too little, too late.

@aradi et al. should pay close attention to such ground realities.

2 Likes

This example is not a floating point exception, but normal error handling, which indeed I think should be the main effort in this proposal. The original example you posted above about floating point exception I think can always be caught with a proper check ahead of time and so I think that use case should be treated separately.

2 Likes

@certik,

Does LFortran support the alternate return facility, or plan to do so? You will know it’s obsolescent but not deleted from the standard.

Once you get alternate return working in LFortran, you should have the wiring in the compiler to start researching error handling options in Fortran, perhaps along the lines of “recoverable” error cases (as opposed to Panic! ones) in Rust or the “throw error values with a standard error type (rather than exceptions)” proposal in C++.

Practical research along those lines with perhaps stdlib in the mix might get LFortran closer to something useful for the use cases of interest shown by @aradi, @everythingfunctional , etc.

2 Likes

We don’t have alternate returns yet. We’ll have to implement them eventually, since there will be some codes that use them.

Yes, we’ll definitely play with some ideas for exceptions in the future. But as I said, I don’t want to spread too thin, so right now we are focusing on compiling codes, and we do one extra feature, and that is generics. Once we can compile most codes, we’ll do more feature prototyping. However, if you or anybody else wants to prototype exceptions ideas, please do, you can start today. Let me know, I can get you started.

1 Like