We have been asked to take this approach with fpt, but I am not sure that it will work. We have a library of many millions of lines of code, many projects held with the permission of our users. Almost none of it conforms fully to any Fortran standard. Issues like REAL*8 and alphabetic colon characters are easy to fix. Issues like STRUCTURE/MAP/UNION, !DEC$ PSECT and %VAL don’t go easily into standard code (believe me I have tried!). We wind up with lists of dos and don’ts for each project.
It might be interesting to start a thread on the language extensions which are still needed. I would like to know how other users handle them.
A solution for this would be to make this an opt-in: If no standard is given, behavior remains unchanged. But if one on purpose tells the compiler to follow a newer standard, deleting features should not be an issue.
Consider fixed form: It is obsolescent because everyone agrees on the advantages of free form. Still, it is part of the standard because legacy code uses it. That makes absolutely sense. What makes IMHO absolutely no sense is the expectation that one can compile from 1990 and setting a flag like --std=f23.
Most compilers already have the possibility to follow different standards. I therefore don’t see the difficulty with saying “Fortran 2026 introduces a consistent naming for rank/rankof. Unfortunately, this change is backward incompatible. We recommend using this standard for new projects. For old projects either adjust your code or tell the compiler to interpret my source according to previous standards.”
I don’t have a strong opinion about this, but what if the programmers are working under a contract that says their code must conform to a specified Fortran standard? Then if they have fixed source form and don’t to change, their contract cannot specify the Fortran 2023 standard, and they cannot use any of the new features in it. Most new Fortran code is written using free source form, but I do see some fixed form codes that use features beyond Fortran 77.
@MarDie one can indeed do backwards incompatible changes with a compiler. For example LFortran by default disables implicit typing, which means that technically “standards conforming code” will not compile by default. We also disable some other old features, like passing an array section A(:) by its first element A(1).
In the same way, it is possible to change meaning of existing constructs, in backwards incompatible manner.
I think there are two legitimate use cases (that in some ways might be slightly conflicting with each other):
I want production library to always be working, indefinitely. An example is LAPACK, they never change its interface. I don’t want to be updating LAPACK or my code just because the language changed.
I want the language to fix its mistakes and don’t mind updating my code to use the most current language iteration.
What are some of the things that you would like to fix in Fortran that require backwards incompatible changes? Most things can be fixed in a backwards compatible manner.
I have experience of one group trying to port a DEC VAX application to Unix and standard Fortran. They never managed it after a couple of man years of effort.
The VALUE attribute of an argument should be a genuine pass by value. I am tired of explaining to C/C++ programmers that they don’t (and can’t) get what they asked for.
Whole array assignments from scalars is a trip-wire. This was, I think, first implemented in MPX Fortran in 1978 and the simulator community knew then that it was dangerous. The worst simulator error I have seen probably cost a few tens of millions of dollars, but I have seen errors elsewhere which were much more expensive.
Using integers for kinds. Kinds could be a reserved type with type-specific names. Again this is a trip-wire. earth_mean_radius = 637800_dp works fine until you post it into an external subroutine without an interface. If the compiler knew that _dp meant the number was REAL the issue would go away. We have seen several of these.
implicit none is a good start, it is especially annoying for interfaces. B.3 Obsolescent features contains already a list of features that are identified as outdated, the most “popular” ones are probably common blocks and fixed form.
A clear procedure with a clear deadline (e.g. next standard revision) for removal would IMHO be better than waiting until almost everyone found the time to modernize their codes.
Consistency of type/rank/kind as discussed here is also something that should be fixed. Too bad that typeof made it into the standard, but even worse if this glitch will stay forever. Yesterday I’ve started discussion on Interface definitions for assumed size arrays, also something that could be improved. Maybe there is no better solution, but knowing that I won’t be fixed even if there would a solution that is superior in all aspects but backward incompatible is weird.
I also agree with the Zen of Python: “Namespaces are one honking great idea – let’s do more of those!” and would like that use math makes functions available as, e.g, math%eigenvalues instead of cluttering my namespace. Compatibility with existing code would then require something like use math as *. Of course, one could make the better option opt-in (as with implicit none) but I think a good language has reasonable defaults and the option to do stupid things instead of stupid defaults and the option to do things right.
Edit: I forgot the newest flaw enumeration and enum: Flaw with typed enumerators in F202X. This should be straightened before the new feature finds widespread use.
I think we have automated pretty well everything in VMS to Linux migration - though I suspect that the codes still have a few surprises waiting for us. There are three groups of issues:
The ‘ordinary’ Fortran, with mis-matched arguments, different argument passing protocols, parameter values found from %LOC, exciting keywords like DICTIONARY and DEFINE FILE. fpt does all of these.
The VMS system libraries and ISAM file handling. Sector7 does these, and fpt sets up the calls.
DEC$ directives. Some of these we have automated and some have to be checked by hand. With these we have to use the Intel compilers - they are VAX-friendly - great job!
It would be tedious and more error-prone to have to set x(:,:,:) to 0.0 with a triple loop, and array values that are used before they are set are a common source of error.
I think almost all the things you mentioned can be fixed in a backwards compatible manner. Even the typeof I think. Usually by adding some syntax / semantics, and deprecating the old one. And good compiler defaults will make it easy to naturally use the most current form, with good error messages and warnings for the old form.
nice, even better if things can be done backward compatible.
A short comment on the proposal: I once read an article about Rust, where the authors showed that Rust nudges users towards the preferred solution while still giving them the freedom to do what they want. It was mentioned “variables” are read-only by default and it takes the extra mut specifier to make them mutable. Similarly, safe code is the default and the use of unsafe code requires an extra unsafe label. I found that very intriguing. Hence, I would prefer if namespaces are enabled by default and extra effort is needed for not using namespaces.
Even though that feature is in the accepted list for f202y, I think it’s being dropped. Besides some apparent issues with scoping rules, one argument for dropping it (weak, imho), is that it might require too much typing as opposed to the ONLY, local_name => entity_name. ... feature we have right now.
Well, I was really hoping for this to go in. The main objection seems to be:
Furthermore, module names are not passed through subsequent use or host
association, which means it would only work in a scope that directly uses
the module. That would make the feature useless. Passing module names
through use or host association, as class one identifiers (which they are),
cannot be changed without introducing an incompatibility.
Does anybody understand what exactly the issue is here? Yes, one “passes” implicitly the module name into nested scopes, just like in Python. What exactly is the incompatibility? If you declare a local variable of the same name as the module, it will shadow it.
$ cat integration_tests/module_namespaces_01.f90
module module_namespaces_01_mod
implicit none
integer :: dummy = 3
end module
program module_namespaces_01
use, namespace :: module_namespaces_01_mod
implicit none
print *, module_namespaces_01_mod % dummy
end
$ lfortran integration_tests/module_namespaces_01.f90
warning: Namespace for modules is an experimental prototype
--> integration_tests/module_namespaces_01.f90:11:10
|
11 | print *, module_namespaces_01_mod % dummy
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Note: Please report unclear, confusing or incorrect messages as bugs at
https://github.com/lfortran/lfortran/issues.
3
I just used single %. (I actually think Fortran should just use . instead of % like every other language, but that’s a separate issue.)
Let’s bring the examples of incompatibility or of things that “cannot be done” as Fortran code using the current prototype above and let’s figure out how to make it work.
I agree with you strongly. All of the errors we have seen from whole array initialisation from scalars were failed attempts to write loops to initialise arrays - the users missed out the array indices on the lef-hand-side.
A possible way of replacing the construct would be with an intrinsic subroutine, e.g.
CALL FILL(xa,0.0)
But the only way to remove the trip-wire would be to make whole array initialisation from scalars across the = sign illegal, and that would now break a lot of codes - including mine.
I am very strongly in favour of this feature. We have, accidentally, prototyped it to some extent. When fpt references a variable, sub-program etc. it uses a %-separated path from the top-level to the final name, e.g.
show symbol %module_subprog
show symbol <module<%module_subprog%internal_subprog%type%component
We have not yet found a case where this does not work.
I have found a use-case where transmitting a module name to its users will fail. We have found several programs written with libraries where the same module name occurs in two or more of the libraries with different contents. From our point of view this is a disaster - when we see all of the code we can’t know which of the modules with the same names are to be used. For this reason I would like to see the module name carried down - it would force users to sort out the problem. People love to have modules called kinds, precision, constants…