Backwards compatibility in different programming languages

I would point out that Python has:

  • introduced backwards incompatible syntax (in few cases on purpose even if they didn’t have to)
  • did not provide reliable tooling to automatically upgrade large code bases to the new syntax
  • removed support of the old syntax from the compiler (interpreter)

In Fortran, even new compilers are implementing features that are even deleted from the standard (e.g., we implemented all kinds of assigned goto statements just a few weeks ago in LFortran). Fortran has introduced backwards incompatible syntax (free form). All compilers (even new ones) support the old syntax (it took us a few months to get a reliable fixed-form parser into LFortran).

If we introduce backwards incompatible change, we have to provide reliable and automatic tools to upgrade code bases. And we can’t remove support for the old feature from compilers, but as I’ve shown above, this is not even on the table.

All in all, I think the lesson from Python is not that we can’t introduce backwards incompatible changes, but rather all three points above is what we should not do. Old code must keep running.

9 Likes

This is entirely a warning without any merit whatsoever in the context of this Discourse that commenced in 2020.

There are essentially 2 utterly detrimental features that have in essence provided no redeeming benefits since 1980 that are being requested to be removed from the language around a decade from now, only because ripping these two from the “root” in the standard and throwing them out is the only path forward other than status quo:

  1. Remove from the standard implicit mapping, thus implicit none becomes the default in every standard-conforming program unit and interface body
  2. Remove from the standard implied save, so that an assignment-based definition on a type declaration requires an explicit SAVE attribute specification

Of the two, it’s the first one with a wide impact since every new Fortranner would immediately need to be “lectured” on it and many are “lost” at such a “hello”. There is absolutely no basis for any computing enthusiast in 2032 starting to author in Fortran to be encumbered by FORTRAN’s one error-prone legacy imparted around the 1950s when so much else in the language has been deleted outright.

Regardless, it is only the standard-conforming code that would be affected by the requested changes.

A case in point is NASTRAN’s BISLOC as discussed previously on this site. It is an example of legacy code which is already broken in several ways relative to the standard, yet which can still be used with all the Fortran processors today. Removal of implicit mapping will be the least of its problems - how does one break something that is already broken? That is really bulk of legacy FORTRAN code - already broken vis-a-vis every edition of the standard starting ANSI 1966.

Additionally, with implicit mapping, the codes can easily get back the legacy feature with the introduction of a single line:

implicit integer(i-n), real(a-h,o-z)

Concurrent to all this is the fact most Fortranners don’t know how to conform and the compiler vendors are more than willing to oblige their “indulgence”. The only compulsion anyone ever feels is having to introduce the ridiculous implicit none statement in every module, main program, and interface body so that they don’t come across as daft. Other than that, the FORTRAN codes are ever ready to “start world war III” given their tendency to not conform and the leeway given to processors to do anything with nonconforming code. This is totally different from the Python 2 / 3 situation.

There is in effect no comparison with the above 2 requests for backwardly incompatible feature changes in Fortran with what is being “suffered” by Python 2 apps.

You have stated this in the past, and just as with the current claim, it makes no sense.

In both cases, old standard-conforming code would not compile without errors. The programmer, who we are assuming is not fluent with fortran, is required to do something to make the code compile. Or they just throw the code away and look for code in another language, possibly never to touch fortran again after the bad experience.

That, simply put, is the risk of introducing backward incompatible changes to the language.

2 Likes

old and standard-conforming! That’s a hoot, alright!

The language standard for Fortran has deleted quite a few features that are error-prone and more detrimental to current and future practitioners than beneficial:

  • arithmetic IF,
  • nonblock DO construct,
  • Hollerith edit descriptor

to name a few. These features are actually employed in legacy codebases at a far greater frequency than implicit mapping, the latter being understood since 1970s, i.e., over 50 years ago, as pernicious and for which the implicit none alternative as a non-standard extension was immediately accepted by practitioners, so much so that the Fortran 90 standard over a dozen years after the ANSI 77 version had no recourse but to standardize it.

So did the sky coming falling down because the above features such as arithmetic IF, nonblock DO, Heolleriths, etc. - staple features in “old” codes - were deleted from the standard and because a conforming compiler would throw errors at compile time?

No. in fact the few and far in between folks, who look at the old FORTRAN code and are mostly revulsed by it, are happy if the compiler can give them some meaningful guidance to move forward. Some processors go out of their way like Intel which forces its users to do extra work to get new, standard-conforming behavior. So what is the problem with old code and future standard revisions? There is none, actually.

On the other hand, the voting members of the Fortran committee can be quite blasé when it is convenient for them to make subtle breaking changes which can silently and adversely affect program behavior such as the one change in Fortran 2023. None of the voting members nor the Community here appear to be bothered by it. Sure if a Fortran 2018 program being actually used in industry fails, so what - hell with it, they can go pound sand is the attitude, let the industry manager(s) budget for a migration to any one of the 20 or so programming languages / platforms that have >99% of the attention and positive rating of practitioners who want to write better and more performant code than with Fortran that has <0.8% rating and which holds on to implicit mapping when an overwhelming majority want to author type-safe code.

The alarm by @RonShepard about backward compatibility above, though kept general, is in reality only alluding to a couple of changes, like implicit mapping and implied save. These needless alarms are only hurting the language and its current and future practitioners besides ignoring and being inconsistent with goes on with Fortran.

The actual history of Fortran is in fact that more than several but consequential backwardly incompatible changes have been made and they continue to happen, like I have listed above.

No, because in practice all major compilers are still accepting them as extensions, just warning that these are deleted features. So old standard-conforming codes at their times still compile. In contrast, with the changes you propose, the compilers would have no choice other than reporting errors for some old codes. For, there would be no way to accept real a=0.0 without save as an extension if the implied save was deleted.

So definitely not the same kind of situation. I admit it would be not as bad, though, as some Python 2/3 changes which result in a silent change of behavior (e.g. the floating point division that becomes an integer division… One of the most stupid decision they could take)

1 Like

I think the compiler would issue a “deleted feature” warning, like it does now for other deleted features. It could even have some helpful information like “hey, did you mean for this to really be implied save? If so, go ahead and add a ,save and move on with your life. If not, you just found a bug.”

I guarantee you that this would help people find bugs they didn’t know about (I’ve found more than one unintended implied save bugs myself over the years).

3 Likes

@PierU, to reiterate for the umpteenth time, no, that is not true at all. It’s entirely up to the processor how it wants to implement the facility, if at all or compel the users to do extra work to get standard-conforming behavior:

   integer :: x(3), i
   do 5 i = 1, size(x)
 5   x(i) = 40 + i
   
   do 10 i = 1, size(x)
      if ( x(i)-42 ) 20, 30, 40
   20 print 21, i
   21 format( 2Hx(, g0, 51H) holds a value less than the answer to everything )
      go to 10
   30 print 31, i
   31 format( 2Hx(, g0, 33H) holds the answer to everything )
      go to 10
   40 print 41, i
   41 format( 2Hx(, g0, 54H) holds a value greater than the answer to everything )
      go to 10
   10 continue
end

The compiler processes this without raising any messages, no trouble with the nonconforming program:

C:\temp>ifort p.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.7.0 Build 20220726_000000
Copyright (C) 1985-2022 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 14.33.31630.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:p.exe
-subsystem:console
p.obj

C:\temp>p.exe
x(1) holds a value less than the answer to everything
x(2) holds the answer to everything
x(3) holds a value greater than the answer to everything

Finally when the program author is compelled by the circumstances to check against the standard and turn on warnings and even treat them as errors:

C:\temp>ifort /c /stand /warn:errors p.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.7.0 Build 20220726_000000
Copyright (C) 1985-2022 Intel Corporation.  All rights reserved.

p.f90(2): error #8869: The labeled DO loop is an obsolescent feature in Fortran 2018.   [5]
   do 5 i = 1, size(x)
------^
p.f90(3): error #8871: The nonblock form of the DO construct is deleted in Fortran 2018.
 5   x(i) = 40 + i
-^
p.f90(5): error #8869: The labeled DO loop is an obsolescent feature in Fortran 2018.   [10]
   do 10 i = 1, size(x)
------^
p.f90(6): error #8870: The arithmetic IF statement has been deleted from Fortran 2018.
      if ( x(i)-42 ) 20, 30, 40
---------------^
p.f90(14): error #7359: The cH edit descriptor has been deleted in Fortran 2018.   [2Hx(]
   41 format( 2Hx(, g0, 54H) holds a value greater than the answer to everything )
--------------^
p.f90(14): error #7359: The cH edit descriptor has been deleted in Fortran 2018.   [54H) holds a value greater than the answer to ]
   41 format( 2Hx(, g0, 54H) holds a value greater than the answer to everything )
------------------------^
p.f90(11): error #7359: The cH edit descriptor has been deleted in Fortran 2018.   [2Hx(]
   31 format( 2Hx(, g0, 33H) holds the answer to everything )
--------------^
p.f90(11): error #7359: The cH edit descriptor has been deleted in Fortran 2018.   [33H) holds the answer to everything ]
   31 format( 2Hx(, g0, 33H) holds the answer to everything )
------------------------^
p.f90(8): error #7359: The cH edit descriptor has been deleted in Fortran 2018.   [2Hx(]
   21 format( 2Hx(, g0, 51H) holds a value less than the answer to everything )
--------------^
p.f90(8): error #7359: The cH edit descriptor has been deleted in Fortran 2018.   [51H) holds a value less than the answer to ]
   21 format( 2Hx(, g0, 51H) holds a value less than the answer to everything )
------------------------^
compilation aborted for p.f90 (code 1)

Also, for certain processors, they can follow something like a “legacy” setting to be nonconforming and let the user continue to resist change:

C:\temp>gfortran -std=legacy p.f90 -o p.exe

C:\temp>p.exe
x(1) holds a value less than the answer to everything
x(2) holds the answer to everything
x(3) holds a value greater than the answer to everything

I think we can all at least agree on the fact that Fortran compilers will support both old and new features. And thus old code will continue to run unmodified (perhaps with some compiler options).

That by itself is a big difference to Python, where the main interpreter (CPython) does not support old syntax, and thus cannot run old code no matter what compiler options you use.

This is the main difference. (We can argue about the details, such as what compiler options should be on by default.)

3 Likes

A standard conforming compiler would be required to issue an error here.

No. If the implied save was to be suppressed, the code above would be illegal. This is not the same as accepting a delete feature which can be considered as an extension.

Right, but nothing prevents compilers to issue such warnings right now when implied saves are encountered, without the need to change the standard.

Sorry but yes again. Your exemple just shows that by default, compilers usually process deleted features as extensions to the standard, which is nothing but new. A compiler can be fully standard-conforming AND accepting extensions. This is not error-prone, as there’s no way to use an “arithmetic if”, a “hollerith”, or a “do without enddo” by mistake.

In contrast, if implied saves were to be deleted from the standard, accepting them by default would be a violation of the standard by the compiler, and above all this would actually defeat the whole purpose of having deleted this feature.

Deleting the implied save would also result in some apparent inconstency: module variables are implicitely saved as well, without requiring the save attribute. Should save be mandatory for module variables as well?

It might also be noted that in the case of Python the transition phase took more than a decade (Eleven years from the first release of Python 3 to the last release of Python 2.). During this phase there was a temporal non-availability of some important libraries for Python 3.
As Steve noted, the change even lead to the disappearance of some programs.
Still, Python 3 is a successful (i.e. widely used and with a lot of available libraries) language now.

I do not know what are the lessions to be learned, but as the user and developer base of Fortran is smaller than the one of Python, even the existing 20XX language standards are (my personal impression) adapted by the users rather slowly, and the person-hours Compiler vendors can invest in the development are limited, two fully parallel lines are in my opinion (I am not involved in developing compilers or essential libraries) just not acceptable.
So the situation might be different for Fortran when compared to python.

Edit: Fixed some typos that made my comment hard to understand.

1 Like

Several matters have been inaccurately conflated here.

A “feature”, regardless of whether it’s a “bug” or worse, is a feature. That in practice implied save gets employed by mistake is not relevant to technical aspects with the language standard. The relevance of this “use by mistake” is with the practical justification to delete the goddamn feature.

Also, the detrimental aspects, e.g., error-prone, around already deleted features, don’t all have to do with oh, someone used the feature by mistake or that they can’t do so. Rather the deletions have do with the accumulated experience where codes and compilers have encountered difficulties, say with nonblock DO, the use of labeled statements in GOTOs and with inner DO loops sharing the labeled statements to end the loops, etc. were leading to significant problems.

Nonetheless, the reality is “old codes” in FORTRAN don’t just die simply because of changes in the standard, there is no equivalence whatsoever with Python 2 / 3. Conflating the Python 2 matters with the Fortran standard is not right.

Separately, the semantics around the SAVE attribute of module variables and main programs are provided separately and there is no need to conflate them with local objects in subprograms.

To make a long story short, the two “features” of implicit mapping and implied save can be removed from the language standard with the maintainers of “old codes” not even realizing anything had changed unless they went looking for it. But that positive change in the standard, earliest it can happen is likely 2033 or so the standard revision cycles, can help the future practitioners. It is a practical matter involving vision toward the feature.

1 Like

@Jweber good points, I agree.

Note that there is no “standard conforming compiler”. The closest is probably the NAG compiler, but even NAG is not 100% standards conforming.

Another note: in LFortran the implicit typing is not allowed by default, you get an error message. If you want implicit typing, you enable it with an --implicit-typing compiler option. We can later add --std=F2018 style options to try to enforce a given standard exactly. Right now we are focusing on simply adding all the options / modes that people would like (well actually our main focus right now is just implementing features to compile more codes). Typically you run a compiler via some build system anyway, whether cmake or fpm. If you have tips what modes we should support and how to make it easy for people to choose them, let us know.

1 Like

“significant problems” is just a rewording of “error-prone”

The fact is that deleting the implied save from the standard would NOT be similar to the past deletions of “arithmetic if” and others.

1 Like

That is not a fact, it’s your opinion for which there is too much evidence it is wrong.

Reminder: please let’s not accuse each other of being “wrong”. All of the above are opinions (mine included!), and I actually agree with all of you. What everybody said above is not inconsistent or in conflict, although it might seem that way. I don’t have the time to summarize, but we all agree we do not want breakage. I mentioned above one way how to get out of this, via compiler / tooling support.

Hasn’t backwards compatibility already been broken between Fortran standard revisions? Take the following piece of code:

program main
    implicit none

    integer, allocatable :: i(:)

    allocate(i(5))
    i(5) = 42

    i = (/ 1, 2, 3, 4 /)
    print *, size(i)
    print *, i
end program

When compiled with gfortran -std=f95 I get:

           5
           1           2           3           4          42

However, with gfortran -std=f2003 I get:

           4
           1           2           3           4

I reproduced the same behaviour with an old (2016-version) Intel compiler and one of the latest versions. I’d also reccoment reading Section 1.6 Compatibility in the Fortran 2003 and 2008 standards. It lists some other, possibly less significant, situations where backwards compatibility has been broken.

The reason for this change in program output is due to the reallocation semantics introduced in Fortran 2003. Notably, the previously mentioned Compatibility sections in the 2003 standard does not mention this.

In my opinion:

  1. Any expectation of backwards compatibility is only realistic with the presence of source code and its build system.
  2. If we should care about backwards compatibility (and I think we should!) then we need compiler vendors to provide compiler flags to enforce a standard version.
    Gfortran’s -std flag is a good example of this. Intel is more sloppy in this regard which I don’t like. I also think fpm should have a way for fpm.toml manifests to specify standard compliance, possibly even being mandatory. For comparison Rust’s cargo does this. It’s optional there, but the new command adds it by default.
  3. I think The future of Fortran as an actively used language depends on both the ability to retain backwards compatibility and also on the ability to completely remove obsolete functionality from future language revisions.
3 Likes

I agree with this. In my opinion, no programmer should ever use implied save of local variables, the save attribute should always be specified explicitly. Prior to implied save, the semantics of initialization for local variables (including with DATA statements) for variables that were modified was undefined. Even in f77, where SAVE was first introduced to the language, programmers knew that the explicit save declaration was required. Modern fortran should have reinforced that convention. Instead the standard tried to do an end run and make previously nonconforming code conforming, introducing confusion and also causing problems with multithreaded parallelism. This was a mistake, and it was known at the time by most programmers that it was a mistake. I am still, even today, dumbfounded that this was done to my language of choice.

I personally have mixed feelings about changing the standard now. Code has now been written that used this feature over the past 15+ years, so there is a backwards compatibility issue involved. I hope the standard committee doesn’t make these kinds of unforced errors in the future. Too many of them will kill the language.

But I do agree with the warning idea. Compilers should do this now, preferably by default, and if the standard can be changed to require this warning, with options to make it an error rather than a warning by the programmer, then I would fully support that. That approach does not break backward compatibility, while showing the relatively minor source code change that is required to eliminate the warning messages.

The elimination of implicit typing to me is a different matter. That would invalidate not only legacy code that programmers already use, but also code from textbooks, from netlib, and other established resources. My opinion is that elimination of implicit typing would also kill the language. If there are changes to implicit typing semantics, or to the syntax, the proponents must find a way to do it that maintains backwards compatibility as much as possible with 65+ years of legacy.

When compiling SciPy with LFortran we had to implement several “deleted” features (such as assigned goto, arithmetic if, etc.). So removing those features did not kill the language, but it “invalidated” old code based on the standard, yet in practice there is no problem.