I agree with this but from what I’ve been seeing, if you use any fancy things (that might be supported or not) you start getting performance hits. For example, I had a memory allocation in a polymorphic function:
class(*)
...
!$omp target enter data map(alloc:...)
and when I changed it to type(my_type I got a 10% performance uplift haha
So if you basically write F90 in your more computationally expensive functions you also get speed.
Unfortunately, I know, I had to avoid many OOP useful paradigms for my device backends. Moreover, NVFortran has bugs even with non OOP stuffs. It is not my favorite compiler, but I cannot complain; it comes for free.
I submit bugs often to nvfortran and they have been good at fixing them. The performance we get with OpenACC/do concurrent is very good and it is hard to complain once you’ve nailed it down.
This is a little bit of a tangent in this discussion, but I’ve wondered why type-bound procedures require class() declarations of the passed dummy argument. Why don’t they allow type() definitions too, or even intrinsic integer, real, etc.? The advantages would include the faster executions mentioned here, and also it would allow the compiler to catch argument mismatches at compile time and not just later at run time. Also, how exactly does the non_overridable attribute affect the execution times? Does that fully compensate for the class() hit on performance?
I’ve wondered this too. If you arent planning on extending a class beyond the base class why require the class declaration for TBPs. On the surface, this would appear to be the easiest way to make sure a class is non-extensible.
Because it was (wrongly) decided (in Fortran 2003) that derived types should be extensible (through class inheritance) by default (which requires the passed-object argument to be run-time polymorphic by default, in order not to be in conflict with the former choice).
This choice is actually one of the major design mistakes in the language (in the vein of default implicit typing, default public module entities, default implicit save etc.).
Once the Traits proposal is implemented in LFortran, it will give you all of these possibilities via the sealed attribute for derived types, and through the possibility to implement traits even for intrinsic types.
This will allow you to opt out of the above (bad) default, and enable the use of the type specifier for the declaration of passed-object dummy arguments, with all the benefits that come with it (that you mentioned above).
Unfortunately, and as it is the case for default implicit typing, implicit save, and public module entities, fixing the (botched) default itself would require breaking backwards compatibility.
I would be interested (if anyone knows) how this decision came about. Basically, what is the history of the development of the F2003 OOP facility and why what looks to me like bad decision making happened. I’ve always wondered why the committee didn’t make a separate CLASS type (ala Java, C++ etc) for polymorphism and leave the existing TYPE facility alone. My personal preference would have been that the CLASS keyword never entered the language. I would have preferred a POLYMORPHIC attribute for a derived type like:
subroutine asub(this)
type(atype), polymorphic, intent(in out) :: this
But I guess that offended the “hunt and peck” programmers who never learned how to “touch type” due to the extra few characters they would have to type.
I would say given that most of these features were designed without having a compiler prototype nor iterating with users, it’s not bad, it could have been much worse. But I think one really must iterate with the users, that will fix everything.
Is there still a process for doing something like a separate technical report (or something similar) on features proposed for inclusion in the standard. If I remember correctly, the extensions to the ALLOCATABLE facility that was introduced in F95 and the added C-interop functions introduced inf F2008 were done this way.
The way F2003 was depicted, fits an embedding pattern that was already common in the F90/F95 era, say:
type base
...
end type
type extended
type(base) :: base
...
end type
The OOP model followed by C++/Java/etc., is not the only one (e.g., JavaScript uses prototypes and the class thing is just syntactic sugar). So, I guess it’s okay that they just borrowed the keyword and mimicked something else.
The real problem, imho, is that the OOP facilities from F2003 haven’t been seriously reviewed/enhanced in like 20+ years. The lack of protocols (i.e., traits, etc.) is really overdue.
(And also, the standards committee still insists on having an upfront (waterfall) “work plan”, even though that may mean a decade from standards “work plan” to a feature landing in a compiler.)
I think that would help. But maybe ISO doesn’t like technical reports?
Since a technical report is guaranteed to be included in the next standard, and the committee already assigns “effort” values to features, the review cycle could be:
2 years for producing technical reports.
1 year for preparing/editing standard X, with the technical reports already published —and during this year, new technical reports can be produced, likely to be included in standard X+1.
Of course, big things (like templates, which has its own chapter in F202y), would still require a couple of cycles to be completed.
In general, I agree with @certik’s assessment. But I’ll attempt to provide a bit more historic background from my own research on the topic. The key points are the following:
The cardinal sin was that the Fortran ANSI J3 committee in the early two-thousands made the fatal mistake to adopt type extension/class inheritance (with run-time type inspections, a.k.a. select type) as the basis for Fortran’s OO facilities.
By that time, it was known for at least a decade from other languages (and from Barbara Liskov’s work) that interface inheritance (subtyping) was far superior and didn’t suffer from the problems that afflict class inheritance (Objective-C and Java had introduced “protocols” and “interfaces” in 1990 and 1995, respectively, for that very reason).
J3 either didn’t know about these developments, or simply ignored them. Whether one characterizes this as gross negligence or something worse, it doesn’t reflect well on J3 either way.
Compared to this mistake everything else is “minor details”.
The decision to not use separate class definitions, and to instead use types and modules in order to define the equivalent of a class, was an absolutely correct one, since it was taken from Niklaus Wirth’s Oberon-2. All modern languages (Go, Rust, etc.) work in the same way, and make use of such orthogonality in their design.
In an early paper documenting their work in progress on the type extension facility, J3 actually required the programmer to provide an extensible attribute to a derived type’s definition, in order for him to specifically opt into using class inheritance. See this link.
This would have been still better as compared to what we ultimately got. But for some unknown to me reason, J3 at some point decided to skip the explicit requirement of opting into using type extension, and made the second fatal mistake of making all derived types extensible by default.
So it was one mistake after the other. Even though there was no lack of other languages doing things right.
I agree. Which in my opinion demonstrates that the committee’s process to evolve the language not only was fundamentally broken, but still is.
One look into their planned template feature should be enough to convince anyone that they are still unwilling to learn from modern languages.
Sometimes it is difficult to distinguish between causes and effects. In this case, I would say that the features haven’t been reviewed because they have not been implemented in compilers in order to be used by programmers. If programmers can’t use the features, how can they suggest improvements?
I started experimenting with the OO features in f2003 as they started to become available (which was about 2006 or 2007). But what I did was not portable because the features were implemented only in parts, and different compilers selected different parts in their path to implementation. So I only experimented with the features in small toy programs, not my actual application codes. One thing I did was a binary search tree (BST) module. It worked by doing the BST operations (adding nodes, removing nodes, printing nodes in order, balancing the tree, etc.) on the basic data structure, and then allowing the basic data structure to be extended by the programmer for each application. It took until about 2016 before the ifort compiler could compile and execute the code correctly. The gfortran compiler only started to compile and execute the code last year, 2025.
I did not do anything fancy in that code, it was all pretty much simple and straightforward. And it took some 20 years after the features were included in the language standard before I could rely on it being supported by two of the most popular compilers I was using. Of course, one of those compilers has now been replaced during that time, so over those long time scales, everything is a moving target and nothing is rock solid certain.
@kkifonidis - IIRC, the designers of the F2003 OO features were trying to avoid problems c++ had encountered (e.g., multiple inheritance), and were looking back to SIMULA-67 as their inspiration.
@jwmwalrus - the F90/F95 style you show is “type inclusion” (i.e., a “has a” relationship). The alternative “is a” relationship is type extension - as F2003 provided.
It is a shame it took so long for various Fortran compilers to incorporate F2003 features. But at the same time, several commercial compiler groups were being disbanded. (Some never survived F77->F90.) More open development projects such as g95->gfortran had yet to ramp up.
Instead of looking at languages of the 1990ies (e.g. Java) that had recognized the actual cause of the problems and had solved them, J3 went back to a language of the 1960ies for inspiration that had introduced the problems in the first place.
Type extension is antithetical to what modern-day OO is about. It has absolutely no place in modern OO because it breaks data abstraction (encapsulation + information hiding), and because it inherently leads to violations of the Liskov Substitution Principle.
Back in 1967, its introduction by Nygaard and Dahl was an unfortunate mistake (as they couldn’t yet know anything about the necessity for information hiding, or about Liskov’s work). But its continued use and promotion today is simply inexcusable.
Regarding the nonsensical “is a” and “has a” terminology: see this video of Robert C. Martin.