When I read this sentence, I immediately thought of several exceptions. Expressions involving constants are often evaluated at compile time rather than run time. Small integer exponents **2, **3, **4
and so on are often special-cased by inlining the multiplications. As for intrinsic math functions, many of them are computed in a nontrivial way in order to avoid large errors, unnecessary overflow, or unnecessary underflow. hypot()
is one that comes to mind – it would surprise me if any compiler computes that function in the “obvious” way.
And generally speaking, compilers are literally full of various optimizations light-years ahead naive implementations.
I think a Fortran compiler needs to special case many of such “special functions” in order to generate high performance code. Often times there are many “bit tricks” that you can do for the given architecture to quickly implement things like abs(x)
and even many conditions such as if (modulo(N, 2) == 1) x = -x
can be quickly implemented using two bit instructions or so. Even if the hardware doesn’t have any instructions that fit, just by using a specialized algorithm one can get far, including those sinpi
functions the compiler could “pattern match it” and replace sin(pi*x)
with sinpi(x)
internally.
Agree, but this is all a distraction and deflection by some here from the point by @tyranids , which is quite valid, in that the practitioners of Fortran deserve committees working on its standard who can introduce both
- trivially simple intrinsic functions such as “ACOSD, ASIND, ATAND, ATAN2D, COSD, SIND, and TAND are trigonometric functions in which angles are specified in degrees” that no compiler implementation should “break a sweat” to implement and
BITS
type andSTRING
type, which too should not be difficult for a Fortran processor to support and if such features are so onerous for them, then the compilers should take firm inspiration from Absoft and Lahey Fortran. And the basis here for a standard committee should not be some crazy notion of an out-of-reach “perfect” design, but one that is a reasonably good option that meets most of the use cases communicated by the practitioners, a la Pareto Principle.
The wikipedia entry says " Fortran […] is a general-purpose, compiled imperative programming language that is especially suited to numeric computation and scientific computing."
The last part of the sentence is as important as the first part.
This wikipedia page may be useful about the word “general purpose”:
Early programming languages were designed for scientific computing (numerical calculations) or commercial data processing, as was computer hardware. Scientific languages such as Fortran and Algol supported floating-point calculations and multidimensional arrays, while business languages such as COBOL supported fixed-field file formats and data records.
Since PL/I, the distinction between scientific and commercial programming languages has diminished, with most languages supporting the basic features required by both, and much of the special file format handling delegated to specialized database management systems.
GPL vs. DSL[edit]
The distinction between general-purpose programming languages and domain-specific programming languages is not always clear.[2] A programming language may be created for a specific task, but used beyond that original domain and thus be considered a general purpose programming language. For example, COBOL, Fortran, and Lisp were created as DSLs (for business processing, numeric computation, and symbolic processing), but became GPL’s over time.[dubious – discuss]
The above “dubious” link is this page (which I think could be edited if necessary):
IMHO, the word “general purpose” has no unique meaning, but I usually feel some language as “general purpose” if it has been used both for numerical computing/simulation, systems programming (to some extent), and also for video game development (because my old hobby is game programming )
Joking aside, I believe “special-purpose” languages also have definite strengths because it makes programming much easier for a target class of problems (like numerical computing). But I still feel Fortran lacks “modern commodity (useful functionality)” usually available in similar special-purpose languages (e.g. builtin support of flexible strings and containers like list and dictionary).
Its kind of interesting how people parse the term “general-purpose” differently. I’ve never considered Fortran to be be a “general-purpose” language in the context of being able to use it to do any programming task (say write a hardware device driver or a complete compiler in addition to crunching numbers). To me it’s always been a language for numerical computing (ie number crunching). In that context, “general-purpose” means to me that it can be used for a wide range of applications across many disciplines from engineering, to astrophysics, to finacial services etc. However, modern analysis methods sometimes require the language to supply functionality like flexible strings and intrinsic containers that are on the same level of importance as doing floating point calculations. Unstructured grid methods in CFD and FEM are example where intrinsic support for things like lists, trees, nearest-neighbor searches, unordered maps etc make the code developers life a lot easier. Sadly, that fact seems to escape the standards committee for some reason. Instead we are given exciting new features like the new array features outlined in section 8 of John Reid’s latest 2023 feature summary (https://wg5-fortran.org/N2201-N2250/N2212.pdf). I guess someone made a case for adding these to the language (and I would be interested to find out what use cases these are suppose to support) but I can’t think of a single instance in the past 50 years I’ve been writing Fortran code that I would ever use these. Particularly, the weird syntax defined in section 8.1. How is this in any way shape or form better than just doing it the old-fashion way. I don’t see that it reduces the amount of characters you have to type etc. if you want an explicit shape rank 3 array just do it the way its been done for 60 plus years. Also, why if we are trying to expand the usability of enumerations is BIND(C) still required. My uses for enumerations (and I use them quite a bit these days) have nothing to do with C-interoperability. Reviewing N2212 I see only a small handful of new features I would have a use for today if they were available in compilers. Mostly a couple of things language features from section 2, the degree trig functions and the at edit descriptor. I don’t see anything else that I have a need for now or anytime in the future.
Is there general agreement that the BITS proposal linked by @sblionel above is a “good enough” option? What are the motivating use cases? Ideally the author of the proposal or the committee would publish those as part of the discussion, but it’s something the community can help with.
The BITS proposal probably handles some (but not all) of the cases for UNSIGNED, which has also been proposed. Are there designs for UNSIGNED that would meet the requirements of BITS?
Readers who are similarly flabbergasted as to what to makes it into the standard and what does not can take some comic relief and view the skit at this link:
Getting a feature in is literally no different than ordering soup!!
“No soup for you” is the vehement response for most practitioners.
As shown in the skit, the whole process is full of “rules” with the end result of it all being extremely biased and discriminatory vis-a-vis the whole reality of diverse practitioner community globally, just as shown with the consumers of the soup in the skit.
Consider a Fortran 2023 feature as summarized in the unofficial WG5 document (!!) available with all the official “watermarks” at the WG5 site on The New Features of Fortran 2023:
Now imagine a practitioner proposing the same: she will virtually be yelled at and insulted no differently than the “no soup for you” as in the skit with the added quip about Fortran already having the short-form a( :, : )
and real, dimension( :, : ) :: a
options, and thus there being no need nor any use for anything with an integer constant with a RANK
attribute. But when an “insider” suggests an extension with ill-defined or undefined use cases, the feature makes it in.
The same happened in the enum
s and enumeration type
s in Fortran 2023 standard. Consider the “initial” features for consideration for the next revision, Fortran 202Y and look at US09 “US09. Allow I/O of enumeration type names” and US14 “Provide scoped access to enumeration enumerators.”
Back in October 2018, I am paying out of pocket and sacrificing vacation to attend J3 meetings in Vegas of all places (try saying that to your family you’re going to Vegas for personal “interest”!) and trying to influence the design of Fortran 2023 feature for enum
s almost five years ahead of the targeted publication date and trying to make the case the standard feature must include “scoped access to enumeration enumerators” and also “IO”. It was effectively no soup for you response with all the anger. Now here are the practitioners five year later with a mostly unusable set of the TWO similar features in the upcoming Fortran 2023 revision and then having to wait until Fortran 202Y with something usabe. That is, hoping Fortran 202Y will correct with the two more worklist items the errors/omissions of Fortran 2023. And the errors and omissions being something precisely what the committee was warned about but which they did not listen. Talk about not doing it right the first time: the current standards process is replete with sheer incompetence, impoliteness, and extreme insouciance.
The new array features can be extremely useful for generic rank-agnostic programming. I have encountered many such use cases in the past that I had to resolve with preprocessing. But I do wish the standard committee went beyond what is offered in 2023 draft. Arbitrary-rank allocatable arrays is an example that I encounter frequently that would be great to see in the langauge. In my opinion the standard committee is taking the right direction in array features, but would be ideal to see it happen on a faster pace.
I figured that it was related to generic ranks. However, the language already has assumed ranks etc. I think the committee’s time would have been better spent trying to expand that capability and remove some of the (to me) arbitrary restrictions on their use.
Yes, that is the obvious objection to this feature. If the RANK()
argument were allowed to be a variable, then that would have been added functionality to the language, e.g. towards generic programming with arguments of arbitrary rank. But as specified, it appears to be simply syntax sugar for functionality that already exists in the language.
Am I missing something here?
No, not from my read of the draft standard. Also, as stated in that “The New Features of Fortran 2023” document, a practitioner still has to use for the argument to the RANK
attribute an “integer constant” such as 2
(or - I will have to check - a constant expression as per the standard). Thus the processor need to be supplied with explicit information on the rank of the array at the time of processing. That is, at compile time.
This may be of some help with preprocessing to achieve Generics.
But the point remains: had such a feature been proposed by someone among a large set of disfavored groups, it would not have seen the light of day. Remember how all proposals “start with minus 100 points” but then somehow some features go from minus 100 to “infinite” points, meaning make the nod into the standard. This entire process is opaque and inconsistent and the common practice of Fortran is left unproductive and not quite enjoyable.
A lack of built-in STRING
and BITS
types is very much part of the unpleasantness. The importance of a built-in type starts with a practitioner not being able to author a derived type with the ( x : y [ : z ] )
“accessor”, a la s(2:3) substring reference with the intrinsic CHARACTER
type, but that is not all. Fortran, since its inception, has had the concept of a processor being able to do certain “magic” that the coders cannot e.g., variadic arguments in MAX
, MIN
intrinsic functions.
This is why some things need to be intrinsic and that includes intrinsic functions, intrinsic subroutines, intrinsic derived types such as STRING
, BITS
, and intrinsic modules such as ISO_C_BINDING
, etc. The committees toward the standard refuse to cooperate fully with this and that’s precisely how they are not serving the practitioners.
Here is the mission statement for Fortran that I proposed a few years ago and that I follow:
The original mission of Fortran that should still be the mission today is: enable scientists, engineers, and other domain experts to write programs that naturally express the mathematics and algorithms employed, are portable across HPC systems, remain viable over decades of use, and extract a high percentage of performance from the underlying hardware.
So the first priority is the numeric computation, scientific computing, high performance and portability (runs on all modern hardware, including GPUs and other accelerators). So even though Fortran is a general-purpose language and you can use it for anything (e.g., the Fortran Package Manager is written in Fortran), I would say one can think of it also as a domain-specific language for scientific computing; it’s not mutually exclusive.
Re: special casing
Compilers do this all the time. Some examples: replacing integer powers with multiplies, or a .5 exponent with SQRT, replacing a combination of SIN and COS of an angle with a single “SINCOS” call. A large part of optimization is pattern matching, which is why I frequently advise users to write clear, straightforward code that the compiler can understand, rather than trying to second-guess what might be “faster”.
Re: BITS
My view is that it was difficult to make a use case for the full BITS proposal given the existing facilities in the language. I don’t quite understand the mentions of unsigned integers in this regard. There have been proposals for an UNSIGNED type before, but it had little support. If you want bit strings, you keep them in integer containers and there is a wide array of intrinsics and other features you can use to manipulate them.
. If you want bit strings, you keep them in integer containers and there is a wide array of intrinsics and other features you can use to manipulate them.
This is indeed what users (I) do. However, the standard mentions “…The model for the interpretation of an integer value as a sequence of bits is in 16.3…”, which makes the use of such features processor-dependent, especially for negative integers. See, e.g., this post for an example of such an “issue”/limitation.
As I’ve written before, the standard tries to describe things in a manner that does not depend on how things are implemented underneath. Once you need to make assumptions about how, say, a processor stores integers, you are outside of what the standard says. That doesn’t mean your code is non-standard, just that it is processor-dependent and it’s your responsibility to make sure that the code does what you want on your target processor.
If you want to extract a bit sequence and treat it as an integer, IBITS
does that - the standard doesn’t say what integer you get because it does not assume a hardware model. Presumably you will deploy your application only on a platform where the dependencies are met.
Re: special casing
Compilers do this all the time. Some examples: replacing integer powers with multiplies, or a .5 exponent with SQRT, replacing a combination of SIN and COS of an angle with a single “SINCOS” call. A large part of optimization is pattern matching, which is why I frequently advise users to write clear, straightforward code that the compiler can understand, rather than trying to second-guess what might be “faster”.
Yes, exactly, I agree with this.
I will note that as a user, I want compilers to get much better at this “pattern matching”, and it’s the current limitations of the compilers often forcing users to write unnatural code. For example recently I had to call openblas directly via bind(c), but I would rather just like to write matmul(transpose(A), B)
and the compiler should pattern match it and call the correct routine in openblas automatically. I have not tested Intel, maybe it already does it.
I know that the Intel compiler special-cases some matmul calls, but calling more general BLAS routines would generally require linking in MKL (I can’t see Intel using openblas.)
A historical note - when I was on the VAX FORTRAN project at DEC, I implemented inlining of BLAS2 calls, creating an internal pseudo-language that translated into intermediate representation, then “implemented” the BLAS2 routines in that language. A later phase could then vectorize and/or parallelize it.
@kargl I needed to use the Accelerate framework on macOS which is several times faster than OpenBLAS (it uses some special instructions and hardware that Apple provides on the M1/M2 laptops). I think the -fexternal-blas
option might work with OpenBLAS, but I have not figured out how to call into Accelerate, since the C API is very similar, but slightly different. Here is how to do it in C: fastGPT/linalg_accelerate.c at 4e70c6a0e9f60a1b3c94f18b32c34a6012de1e7b · certik/fastGPT · GitHub and I just ended up calling it via bind(c).