Favourites (I am a domain expert not a computer scientist)
verbosity = a language that tells me what it is doing without having to remember too much
array handling
language defined features that others have to pull in libraries to do
Least favourite
lack of simple introspection: I would really use NAME(), ACTUAL_NAME(), PLACE() functions such as
x = 9.0
call foo( x, 7.4)
...
subroutine foo(a,b)
real, intent(in) a,b
print *, place() ! prints prog name: module name: procedure_name: block_name
print *, name(a)//' = ', a ! prints a = 9.0
print *, actual_name(a) // ' = ' , a ! prints x = 9.0
print *, actual_name(b) ! returns, say, #7.4
! with component equivalents
print *, a % name // ' = ', a
print *, a % actual_name // ' = ', a
Using actual_name() with a non-dummy argument could return the same as name
I think there is utility in a SCOPE() function too, but I may already have said more than enough for compiler writers to put a price on my head. I just feel features like this would be so useful in error handling.
Please don’t get ratty with me if these features already exist.
character (len=*), parameter :: msg = "in module_name::foo, "
and use msg in error messages. One could write a script that defines such a named constant within every procedure. I would like a place() function, but a difficulty of having place() in the language is that the compiler may inline a procedure, so that it does not exist in the executable. Maybe allow the compiler to print UNKNOWN if the information has been lost? Do C, C++, and Java have introspection?
We have compiler_version and compiler_options, so there is some precedent for some kind of introspection.
place() is an interesting idea, and leaves plenty of room for “processor dependent” output, so I think it could be workable. file() and line() have been suggested in the past, but since the standard has no notion of source files. I could imagine the description in the standard being something like “returns a character value of default kind that is a processor dependent representation of the location within the current translation unit”.
name() seems a bit superfluous. You had to type the name of the variable there anyway, just put it in quotes. It would even be 4 characters shorter.
actual_name seems like it probably has too many cases where it doesn’t work. For example, what if the actual argument was a literal? (i.e. 3.14), or even worse, what if the argument was an expression? (i.e. 9.0 / 3.0) In those cases there is no actual name.
I am very glad to note that the LFortran webpage lists the native support for matrices and matrix/vector operations as the top two highlights of Fortran:
This is reassuring, because I thought I was among the minority when regarding such support as a core strength of Fortran, and I even thought I totally misunderstood modern Fortran.
Now, it seems that my understanding of Fortran is at least akin to the viewpoint of LFortran developers. Great! This viewpoint is also an indication that LFortran will pay more attention to the robustness and performance of intrinsic array procedures such as matmul. This gives me yet another reason to look forward to using LFortran for my projects, in addition to many others including interactivity.
Some kind of deep introspection feature would be huge! What I want is the ability to write parser libraries that you can send arbitrary variables to, and it can serialize/deserialize them without requiring the user to manually type all the variable names, etc. The one place in Fortran that has anything like that is the namelist feature. But, if we had introspection, we could create a similar feature for modern formats like JSON or TOML very easily. We’d need variable name, rank, kind, size, etc, and also the ability to traverse derived types.
The ‘.’ field separator for records of structures lived with .AND., .TRUE. etc. from about 1980 to the present - it is well supported by (at least) ifort, CVF, Itanium VMS and HP/UX. It is just possible to construct ambiguities but you have to try quite hard (After the alphabetic ‘:’ in MPX this is hardly a problem). Given the number of type components relative to the number of user-defined operators, surely we can bring the ‘.’ back?
I don’t know about this proposal. Most of us are trying to identify and eliminate ambiguities in the language and find ways to make it easier to parse the language and to write compilers. Introducing a new ambiguous syntax on purpose into the language doesn’t seem like progress in that respect.
I agree that the ambiguity would almost never come up, but it seems like it would make things confusing for beginners. Do you teach them “use ‘.’ for component references, except maybe you’ll get a confusing error and in that case use ‘%’”?
I think that we must accept the current situation that the ‘.’ separator is, and has long been present. I could take you to over 10 million lines of aerospace design code which is re-used whenever a new vehicle is planned, which uses STRUCTURE/MAP/UNION with the ‘.’ field separator. We are currently working on a half-million like power distribution code in the same style.
It would generate no more ambiguity to replace the ‘.’ in operators by ‘%’, and I think it would enhance the readability of the code to use ‘.’ for type components. Many new Fortran users have already used C and will expect the ‘.’.
In reply to @RonShepard, I agree that multiple uses for operators and delimiters can cause additional complexity in parsing and static semantics. Our own tools have (small) dedicated handlers to sort out the meanings of ‘.’ (Field separator, operator delimiter, decimal point, literal .TRUE. …), of ‘%’ (Type component separator, field separator (yes you can!), %VAL, %REF, %DESCR etc.) and of ‘:’ (Alphabetic character, range separator). I doubt if this adds more than 300 lines to our code. It can be done, but of course one would prefer not.
If you already have source code tools to parse out the different meanings of “.”, then you could probably adapt them to replace all of the nonstandard component designators with standard ones. Once your code is fixed, you would never need to worry about this issue again, and you would no longer need to rely on your compiler supporting these legacy extensions.
As for %VAL, %REF, etc., those were all nonstandard f77 extensions. Vendors encouraged their use because it locked in their customers to use their compiler. It made it difficult to switch to a different brand of computer the next purchase cycle. The fact that you still have these in your code is evidence that the marketing tactic worked.
Are there any software tools out there, free or commercial, that automatically fixes fortran codes with nonstandard “.”, %REF, %VAL, and so on? There are almost certainly 10s or 100s of millions of lines of legacy fortran code in this condition that are still in use. The ability to easily and reliably port such codes into modern, standard, portable fortran would benefit those users and also the fortran community in general.
We are working towards complete refactoring of old, non-standard constructs in fpt.
Fixed to free format is easy.
For MPX we have handled DATAPOOL, all of the extended memory constructs, alphabetic colons and a useful proportion of the embedded assembler.
For VMS / CVF/ ifort we have tab format, most of the DEC$ constructs, %DESCR, the use of different kinds in real arguments, ISAM keyed I/O and almost everything else.
But we can’t yet replace:
i. %VAL - Fortran pass by value is actually a pass by reference
ii. STRUCTURE/MAP/UNION. It is easy to convert STRUCTURE to derived type if there is no MAP. We are working on a code with 5Gb of array space and heavy use of MAP and UNION. If we didn’t use MAP and UNION it would blow through the available memory.
The dot separator, along with STRUCTURE/RECORD/UNION/MAP, was a VAX FORTRAN extension from 1985, with the belief that the standard (still very much in flux) would come up with something different. There were already ambiguities with operators that the compiler had to have some heuristics to resolve. Fortran 90’s user-defined operators made that even more challenging, and for many years after parsing bugs would show up due to use of the dot separator.
I wasn’t on the committee at the time, but I’ve heard that there were vociferous arguments about which separator should be used - while many will agree that % is “ugly”, it is unambiguous and works.
No - instead, it supported both in parallel, which was its own headache and, in hindsight, probably a bad idea. Keep in mind that the syntax for declaring a standard derived type is very different from a DEC STRUCTURE, and standard Fortran doesn’t use RECORD. But DEC Fortran (and its successors) allowed you to use dot with derived type or percent with STRUCTURE/RECORD. Note also that standard Fortran has no equivalent to UNION/MAP - unions have been proposed but they would not play well with established semantics such as component order.
We looked quite hard at automating the conversion. There are 2 issues:
i. STRUCTURE declarations can be nested - you can define STRUCTURES within STRUCTURES.
You can’t do this with derived types. This was quite easy to handle - fpt has a command to remove nested structures and the nested structure is replaced by a record of an externally defined structure.
ii. MAP and UNION: This we haven’t done yet. You can replace the STRUCTURE with a SEQUENCE derived type. I can then see two alternatives. One is to define a different type for each UNION and to equivalence the variables of the derived types. This could get quite bulky, and of course we don’t like EQUIVALENCE. The other is to create a container in the type and use TRANSFER, and perhaps type-bound procedures to move stuff in and out. Probably inefficient (but if we are replacing something which ran on a VAX who cares) but probably not very clear in the code.
Is there another, better way? I am reluctant to believe that there is something in 1980’s legacy FORTRAN that we can’t do well in standard Fortran.
I avoided using VAX structures for portability reasons, so my unfamiliarity with the details might render this comment meaningless, but you can certainly define derived types that have other derived types as members. It seems like that would be analogous to structures within structures. Also, although this might not apply, you can define a structure to have a member that is its own derived type, i.e. recursively. That can be used, for example, to define networks (graphs) and tree structures and so on. You do this with allocatable members, which are like pointers but are easier to work with.