Is this legal in Fortran: dot_product(x, x)? - fortran

I saw this code on the Internet: dot_product(x, x) Is this "undefined behavior" in Fortran (because of the aliasing)?

No, there is no undefined behaviour there, the dot product of a vector with itself is well defined. The function definition does not require any modification to the input arguments, it would be a bizarre implementation indeed which modified them.
The (2003 and 2008) standard's restrictions on arguments which overlap (or are aliased but that is not the language the standard uses) only apply if a procedure tries to redefine such an argument. That is not the case with the intrinsic dot_product whose arguments, as defined in the standard(s), have intent(in).

I finally tracked down what the FORTRAN 77 ANSI standard has to say about this:
15.9.3.6 Restrictions on Association of Entities
If a subprogram reference causes a dummy argument in the referenced subprogram to
become associated with another dummy argument in the referenced subprogram, neither
dummy argument may become defined during execution of that subprogram. For
example, if a subroutine is headed by
SUBROUTINE XYZ (A,B)
and is referenced by
CALL XYZ (C,C)
the dummy arguments A and B each become associated with the same actual argument C
and therefore with each other. Neither A nor B may become defined during this execution
of subroutine XYZ or by any procedures referenced by XYZ.
So the standard restricts the modification of the aliased arguments rather than their aliasing.

Related

Is the PURE keyword enforced or assumed to be true by a Fortran compiler?

Is a Fortran 90+ compliant compiler required to always reject compiling functions marked as PURE, if the function violates a requirement of being PURE?
In other words, can I be sure (assuming the compiler is bug free), that if I mark an arbitrary function PURE, there will be a compile-time error instead of UB?
Contrast this with restrict in C++, where it is a promise from the programmer to the compiler, that the given pointer/reference is never aliased. The compiler does its job with this assumption and if at any point the pointers are aliased, you get UB at runtime.
In Fortran 2018 all of the constraints listed that apply to a "pure" subprogram are so-called numbered constraints (F2018, 15.7 p.2). This means that the compiler is required to be able to diagnose violations of any such constraint. (In practice, there's little motivation for a compiler to choose to let the programmer off the hook and allow such violations.) A violation of a numbered constraint does not need to be diagnosed at compile-time (instead of run-time), although that's generally the time it would be.
However, the constraints that apply to a "pure" subprogram are not necessarily those that are required to make the subprogram pure in a pure computer science sense.
There is a complementary question which can also be addressed here. The constraints I mention apply to pure subprograms, but these aren't the only places where a programmer can mark a procedure to be pure.
The constraints on pure subprograms apply where we have something we want to compile:
function f(x, y, z)
...
end function
Adding the PURE prefix to give instead
pure function f(x, y, z)
...
end function
is where assessment of the constraints would be expected: something which makes PURE inappropriate for f will elicit complaints.
Consider, though:
subroutine s(f)
interface
pure function f(x,y,z)
...
end function f
end interface
end subroutine s
Here we can add the PURE prefix to the dummy procedure's interface block. But we aren't defining a subprogram here and so the numbered constraints don't apply: we can't expect a compiler to check whether the actual argument procedure is pure. There is no numbered constraint (or syntax rule) which says the interface block must be correct for the ultimate use. That's our responsibility as a programmer, and one the compiler may trust we give take seriously. Your compiler will make a good stab at checking and pick up many cases, but it doesn't have to account for our wilful desire to obfuscate.
If you are writing a Fortran function yourself and mark it pure then the compiler must check that it conforms to the requirements. However, there are many options where you can lie to the compiler and slip a non-pure external (or even a non-Fortran) function where a pure function is promised in an interface block. In such cases it is indeed a promise even if holding it is required by the standard and violating it makes the prohram non-conforming and thus non-Fortran.

Type-bound assignment reinitializes the members to zero [duplicate]

According to the Fortran standard:
The INTENT (OUT) attribute for a nonpointer dummy argument specifies that the dummy argument becomes undefined on invocation of the procedure
However this simple code gives me 5 as output, so it seems the argument didn't become undefined at the start of the procedure (in this case a subroutine).
subroutine useless(a)
integer, intent(out) :: a
print *,a
end subroutine useless
program test
integer :: n=5
call useless(n)
end program test
What am I getting wrong? It seems that intent(inout) and intent(out) are the same.
intent(inout) and intent(out) are certainly not the same. You have noted why, although you don't draw the correct conclusion. On entering the subroutine useless a is undefined, rather than defined.
Having a variable "undefined" means that you cannot rely on a specific behaviour when you reference it. You observed that the variable a had a value 5 but this does not mean that the only value you could observe is 5. In particular "undefined" does not mean "takes a specific value like NaN".
Your code is not standard conforming because of this reference to an undefined variable. See Fortran 2008 6.2 (similar meaning will be somewhere in Fortran 90 as initially tagged). Of particular note is that the compiler doesn't have to point out your mistake.
With intent(inout) the variable a would be defined when referenced and it will be guaranteed to have the value 5 (for a conforming processor).
More widely, there are other differences between the two intent attributes and this "coincidental" appearance of the similarity of the definition of the variable a could be more troublesome.
Allocatable arrays and objects with deferred type parameters, for example, are deallocated; derived types become undefined (and any allocatable components deallocated) and components with default initialization are "re-initalized"; pointers have their association status become undefined.
All of these latter things have potential for very awkward results, much more so than with a scalar integer, if they are referenced without being defined first.

Can Fortran PURE functions use global parameters?

It seems to me the what is called a pure function in Fortran is not considered pure enough for those who use functional programming. So here is my question. Suppose I have the following code:
MODULE basics
IMPLICIT NONE
INTEGER, PARAMETER :: dp = kind(1.0d0)
REAL(dp), PARAMETER :: PI=3.1415926535897932_dp
REAL(dp), PARAMETER :: earthEquatorialRadius=6378.137_dp
END MODULE basics
MODULE myFunctions
USE basics
IMPLICIT NONE
PURE REAL(dp) FUNCTION sphericalArc(angleInRadians)
REAL(dp),INTENT(IN) :: angleInRadians
sphericalArc= 2.0*PI*earthEquatorialRadius*angleInRadians
END FUNCTION sphericalArc
END MODULE myFunctions
The function sphericalArc has no side effects, so it's pure in that sense, but it uses global constants. It's true that the parameters PI and earthEquatorialRadius can be defined inside the function but this is undesirable since I would like to use these in other functions and subroutines. It's going to be even more tedious to make the dp type defined in each function or procedure.
So from Fortran's perspective is a function that uses global parameters defined outside of the function still considered pure and can be called from a do concurrent loop?
If a Fortran procedure (function or subroutine) has the pure prefix in its definition then it is a pure procedure in the sense that Fortran uses it. It can then be used in places where there is a restriction of purity. A procedure with prefix elemental and without the prefix impure is also pure.
To be allowed to be specified as pure, the procedure is subject to a number of constraints, but it is necessary for the compiler to diagnose any violation of these constraints when pure is given.
There is no constraint that a named constant from another module (or other scope) may not be referenced.
As motivation for purity in Fortran, the standard (F2008, Note 12.49) offers:
The above constraints are designed to guarantee that a pure procedure is free from side effects (modifications of data visible outside the procedure)
Referencing a named constant is not modification of data visible outside the procedure.
From this documentation it should be okay to use a global variable as long as it is a parameter (so the value does not change).
The execution_part and internal_subprogram_part of a pure procedure
cannot refer to a dummy argument with an INTENT(IN), a global variable
(or any object that is storage associated with one), or any subobject
thereof, in contexts that may cause its value to change: that is, in
contexts that produce side effects.

How are quantities referenced in Fortran?

I was told a long time ago that in FORTRAN, everything is passed by value. Therefore I would need to do this (provided mySubroutine is suitably defined elsewhere):
double precision :: myArray(2)
myArray(1:2) = (/ 2.3d0, 1.5d0 /)
CALL mySubroutine(myArray)
However, I also found that the program compiles and runs as expected if I do this
CALL mySubroutine((/ 2.3d0, 1.5d0 /))
without needing to define an intermediary array myArray. I thought that I was passing myArray into mySubroutine by reference. What is going on under the hood in the second version? Is the compiler unpacking the subroutine call, declaring a temporary variable only to pass it by reference?
To a large extent, trying to classify Fortran procedure calling with pass-by-reference and pass-by-value is not too helpful. You can find more detail on that in response to questions like this one and this one.
In short, generally procedure references are such that changes to a variable in a procedure are reflected in the variable where the procedure was referenced. In some cases a compiler may choose to do copy-in/copy-out, and in others it effectively must. Equally, the value attribute of a dummy argument specifies that an anonymous copy be made.
Where this question adds something a little different is in the use of an expression such as in
call mySubroutine([2.3d0, 1.5d0]) ! Using F2003 array constructor syntax
Is the compiler creating a temporary variable?
Admittedly, this is perhaps just a looseness in terminology but it's worth saying that there is certainly no variable involved. [2.3d0, 1.5d0] is an expression, not a variable. Crucially this means that it cannot be modified (appear in a variable definition context) in the procedure. Restrictions that apply in the case using an expression rather than a (temporary) variable include:
the dummy argument associated with an expression may not have the intent(inout) or the intent(out) attribute;
if the dummy argument hasn't an intent attribute then that argument may not be modified if the associated actual argument is an expression.
Now, if the dummy argument has the value attribute the effect of the procedure is the same whichever way it is referenced.
To conclude, the program may work just as well with an expression instead of an intermediate variable. If it doesn't that's because of violation of some aspect of Fortran. How it works is a problem for the compiler not the programmer.

Can using a lambda in header files violate the ODR?

Can the following be written in a header file:
inline void f () { std::function<void ()> func = [] {}; }
or
class C { std::function<void ()> func = [] {}; C () {} };
I guess in each source file, the lambda's type may be different and therefore the contained type in std::function (target_type's results will differ).
Is this an ODR (One Definition Rule) violation, despite looking like a common pattern and a reasonable thing to do? Does the second sample violate the ODR every time or only if at least one constructor is in a header file?
This boils down to whether or not a lambda's type differs across translation units. If it does, it may affect template argument deduction and potentially cause different functions to be called - in what are meant to be consistent definitions. That would violate the ODR (see below).
However, that isn't intended. In fact, this problem has already been touched on a while ago by core issue 765, which specifically names inline functions with external linkage - such as f:
7.1.2 [dcl.fct.spec] paragraph 4 specifies that local static variables and string literals appearing in the body of an inline function with
external linkage must be the same entities in every translation unit
in the program. Nothing is said, however, about whether local types
are likewise required to be the same.
Although a conforming program could always have determined this by use
of typeid, recent changes to C++ (allowing local types as template
type arguments, lambda expression closure classes) make this question
more pressing.
Notes from the July, 2009 meeting:
The types are intended to be the same.
Now, the resolution incorporated the following wording into [dcl.fct.spec]/4:
A type defined within the body of an extern inline function is the same type in every translation unit.
(NB: MSVC isn't regarding the above wording yet, although it might in the next release).
Lambdas inside such functions' bodies are therefore safe, since the closure type's definition is indeed at block scope ([expr.prim.lambda]/3).
Hence multiple definitions of f were ever well-defined.
This resolution certainly doesn't cover all scenarios, as there are many more kinds of entities with external linkage that can make use of lambdas, function templates in particular - this should be covered by another core issue.
In the meantime, Itanium already contains appropriate rules to ensure that such lambdas' types coincide in more situations, hence Clang and GCC should already mostly behave as intended.
Standardese on why differing closure types are an ODR violation follows. Consider bullet points (6.2) and (6.4) in [basic.def.odr]/6:
There can be more than one definition of […]. Given such an entity named D defined in more than one translation unit, then each definition of D shall consist of the
same sequence of tokens; and
(6.2) - in each definition of D, corresponding names, looked up
according to [basic.lookup], shall refer to an entity defined within
the definition of D, or shall refer to the same entity, after
overload resolution ([over.match]) and after matching of partial
template specialization ([temp.over]), […]; and
(6.4) - in each definition of D, the overloaded operators referred to,
the implicit calls to conversion functions, constructors,
operator new functions and operator delete functions, shall refer to
the same function, or to a function defined within the definition of
D; […]
What this effectively means is that any functions called in the entity's definition shall be the same in all translation units - or have been defined inside its definition, like local classes and their members. I.e. usage of a lambda per se is not problematic, but passing it to function templates clearly is, since these are defined outside the definition.
In your example with C, the closure type is defined within the class (whose scope is the smallest enclosing one). If the closure type differs in two TUs, which the standard may unintentionally imply with the uniqueness of a closure type, the constructor instantiates and calls different specializations of function's constructor template, violating (6.4) in the above quote.
UPDATED
After all I agree with #Columbo answer, but want to add the practical five cents :)
Although the ODR violation sounds dangerous, it's not really a serious problem in this particular case. The lambda classes created in different TUs are equivalent except their typeids. So unless you have to cope with the typeid of a header-defined lambda (or a type depending on the lambda), you are safe.
Now, when the ODR violation is reported as a bug, there is a big chance that it will be fixed in compilers that have the problem e.g. MSVC and probably some other ones which don't follow the Itanium ABI. Note that Itanium ABI conformant compilers (e.g. gcc and clang) are already producing ODR-correct code for header-defined lambdas.