I would like to know whether it is possible in modern Fortran to assign an allocatable array using itself, or part of it, to do it. Here it is a simple example:
module modu
implicit none
type :: t
integer :: i
end type
contains
subroutine assign(a,b)
type(t), allocatable, intent(out) :: a(:)
type(t), intent(in) :: b
allocate(a(1))
a(1) = b
end subroutine
end module
!----------------------
program test
use modu
implicit none
type(t), allocatable :: a(:)
allocate(a(1))
a(1)%i = 2
call assign(a, a(1))
print*, a(1)%i
end program
This code gives the corect answer with ifort 18 and returns "Segmentation fault" with gfortran 7.4.
NOTE: The original problem was a bit more complex since call assign(a, a(1)) should be replaced by call assign(a, a(1)+b) having operator + properly overloaded, but the conclusion (respect ifort and gfortran) is the same.
NOTE: In the thread checking for self-assignment in fortran overloaded assignment, #IanH makes a distinction between call assign(a,a) and call assign(a,(a)) but I believe that it does not solve this problem because I have allocatable arguments.
NOTE: In the thread Automatic array allocation upon assignment in Fortran, #francescalus explains automatic allocation on intrinsic assignment but again I believe that it does not apply here.
This call
call assign(a, a(1))
is forbidden by the aliasing rules of Fortran. You are passing the same value in different arguments and neither is pointer or target and you are modifying one of them.
Then, the compiler deallocates a because it is intent(out). That means that the old a(1) no longer exists. But b still points there. Then you allocate a new a somewhere else. Then you try to use b in
a(1) = b
and that is bound to fail because it points to some undefined piece of memory. You are just lucky with Intel Fortran, but your code is illegal. Maybe Intell allocated the new a to the same place where the old a was, but that is pure luck.
It will work if you do
type(t), allocatable, intent(inout) :: a(:)
type(t), value :: b
deallocate(a)
allocate(a(1))
a(1) = b
I am not sure, why it crashes with intent(out) and value. It may be a problem with the compiler, reported as bug 92178.
It is possible to assign to an allocatable array using array elements of that same array. For example, for a allocatable
a = [a(2), a(1)]
is valid and has the expected result. This is the same whether a is an intrinsic type (for intrinsic assignment) or of derived type (for intrinsic or defined assignment). The right-hand side is treated as evaluated fully as an expression before the left-hand side becomes affected.
However, using call assign(a,a(1)) is not the same thing as this assignment.
The point in the answer by IanH you reference is relevant here. Defined assignment would be like call assign(a,(a(1))) rather than call assign(a,a(1)).
This is important because of the aliasing restrictions mentioned in Vladimir F's answer which I won't repeat. Using call assign(a,(a(1))) removes the aliasing because (a(1)) is an expression with value that of the array element rather than the array element itself. This is similar to the value attribute Vladimir F mentions, but without creating a definable entity.
Defined assignment uses the (rhs) construct precisely to avoid this aliasing issue.
Regarding your gfortran results, IanH created a bug report for GCC in response to that other question. It may well be relevant in explaining the surprise you have here.
Related
I'm trying to learn Fortran, and I've found that there aren't very many tutorials out there (probably due to it being an old language). The ones I have found are vague and undescriptive, and as I've gone into more complex things it has become harder and harder to guess what said tutorials are saying.My current issue is with creating types. The tutorial contains examples such as:
module m_shapes
implicit none
private
public t_square
type :: t_square
real :: side
contains
procedure :: area ! procedure declaration
end type
contains
! Procedure definition
real function area(self) result(res)
class(t_square), intent(in) :: self
res = self%side**2
end function
end module m_shapes
This compiles fine, so I know it works.
When I try to do something similar like this:
program type_test
implicit none
type :: thingy(a)
real :: a
end type
end program
It doesn't compile with errors like "The component at (1) that appears in the type parameter list at (2) has neither the KIND nor LEN attribute"
The tutorial I found does not explain types well enough, and I've tried things like real,kind :: a = kind(0.0), but to no avail. Does anybody know what's wrong?
Thanks in advance.
You did not explain, what you actually want to do. Or your words are not nearly clear enough. We can tell you why your attempt produces the error, but I have no idea what you actually want to do.
Perhaps you just wanted
program type_test
implicit none
type :: thingy
real :: a
end type
end program
without the (a)? That declares a simple type with one component. But hard to guess if this is what you wanted and what you tried with the (a).
It does not declare any variable with that type. That is done using
type(thingy) :: var
The syntax
type :: thingy(a)
real :: a
end type
attempts to declare a parametrized derived type. These types can depend on a kind or length parameter. These parameters must be integers. If it is a kind parameter, it allows to declare variables of the type with varying values of these parameters. Then the kind of some components of the type (you know what kind is, right? Fortran 90 kind parameter ) get their kind according to the value of the parameter. If it is a length parameter, it allows the length of some array or string components of the derived type to be parametrized - set during the variable declaration.
These parameters that appear in the parenthesis must be integer components and must have the kind or len attribute.
For example
type :: param_type(k,l)
integer, kind :: k
integer, len :: l
real(kind=k), dimension(l) :: array
end type param_type
type(param_type(kind(1.), 10)) :: o_sp_10
type(param_type(kind(1.d0), 20)) :: o_dp_20
The values of the parameters are set during the declaration of those o_sp_10 and o_dp_20 objects. I do not want to go into more details.
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.
If I have an allocatable array of a finalizable derived type, will the finalizer be called on every individual element when the array goes out of scope?
Here is a small code example that illustrates the question:
module LeakyTypeModule
implicit none
private
type, public :: LeakyType
real, pointer :: dontLeakMe(:) => null()
contains
procedure :: New
final :: Finalizer
end type
contains
subroutine New(self, n)
class(LeakyType), intent(out) :: self
integer , intent(in) :: n
allocate(self%dontLeakMe(n))
self%dontLeakMe = 42.0
end subroutine
subroutine Finalizer(self)
type(LeakyType), intent(inout) :: self
if (associated(self%dontLeakMe)) deallocate(self%dontLeakMe)
end subroutine
end module
program leak
use LeakyTypeModule
implicit none
type(LeakyType), allocatable :: arr(:)
allocate(arr(1))
call arr(1)%New(1000)
deallocate(arr)
end program
Note that this program leaks the dontLeakMe array allocated in the New() method of LeakyType. At first this was a bit surprising for me but, then I discovered that the problem can be fixed by declaring the finalizer elemental. Both gfortran and ifort behave in the same way, so I assume this behaviour is following the Fortran 2003 standard.
Can anyone confirm this? To be honest I have a hard time time understanding what the standard says on this particular point.
Right now I also can't see much use in not declaring all my finalizers elemental. Does this have any application I'm overlooking?
The rules for determining whether a final procedure is invoked, and which final procedure is invoked, are the same as for resolution of generic procedures in terms of rank matching requirements.
Noting that the question is tagged Fortran 2003...
Elemental procedures in Fortran 2003 and prior have to be PURE. If your finalizer needs to do something that is incompatible with the pure attribute (which is reasonably common) then the finalizer cannot be elemental, and you need to write the rank specific variants.
Fortran 2008 introduces the concept of IMPURE ELEMENTAL, which is quite handy for writing finalizers.
I got troubles with this common:
COMMON /REDCOM/ DPREC,NITMA,INDIC,NBERR,NCAR,KMOTLU,
& REDVAR,MOCDER(2)
COMMON /REDCO1/ CTEXT
C
type(double_st) :: DPREC
INTEGER :: NITMA,INDIC,NBERR,NCAR,KMOTLU,REDVAR,MOCDER
CHARACTER(72) :: CTEXT
CHARACTER(4) :: CTEXT4
C
EQUIVALENCE (CTEXT,CTEXT4)
The double_st derived type is:
type double_st
sequence
real(kind(0.d0)) :: x,y,z
integer :: acc = -1
end type double_st
Trying to compile some code including this common, I get:
ifort:
./REDCOM.INC(1): error #6005: A derived type object in a COMMON block shall not have default initialization [DPREC]
COMMON /REDCOM/ DPREC,NITMA,INDIC,NBERR,NCAR,KMOTLU,
----------------------^
gfortran:
REDCOM.INC:1.27:
Included at m_abaq4.f:90:
COMMON /REDCOM/ DPREC,NITMA,INDIC,NBERR,NCAR,KMOTLU,
1
Error: Derived type variable 'dprec' in COMMON at (1) may not have default initializer
Being not very familiar with Fortran, I don't understand what the problem is, or how to solve it (I tried googling with no success). If I use a REAL(8) instead of a double_st, everything works fine.
Could someone help me on this?
From the line
integer :: acc = -1
strip off the trailing
= -1
to leave
integer :: acc
recompile, and see what happens. The error message suggests that a program can't initialise a derived type component and use variables of that derived type in common statements. 'Initialize' is used in the Fortran standards to mean, precisely, the setting of a variable (or element) 's value in its declaration.
In my (draft) version of the Fortran 2008 standard constraint 506 on rule 503 prohibits initialization of components of variables of derived type used in common blocks. This prohibition doesn't seem to apply to initialization of variables of intrinsic types, hence the compiler's acceptance of the code when the variable is of type real(8).
As for using derived types in common blocks, that's mixed-paradigm programming if ever there was such a thing !
I'm saying much the same as in High Performance Mark's answer, but hopefully with a little more elaboration. After that answer's edit I actually diverge a little.
Having the type declaration
type double_st
sequence
real(kind(0.d0)) :: x,y,z
integer :: acc = -1
end type double_st
involves default initialization. That's the acc=1 part: see Fortran 2008 4.5.4.6. It isn't just the component that is default initialized but the whole type.
There is a constraint (C5105, in 5.7.2.1) which says that
If a common-block-object is of a derived type, the type shall have the BIND attribute or the SEQUENCE attribute and it shall have no default initialization.
This is what the compilers complain about. Using a real(kind(0d0)) (or real(8)) doesn't violate this constraint. Intrinsic types (such as that real) cannot have default initialization, but they can have explicit initialization (such as real :: hello = 1.). There are some restrictions on the use of an explicitly initialized object (such as C506 mentioned in the other answer), but the question isn't clear enough on that point for me to comment further.
I had a question about the correct way of programming user-defined operators in Fortran. To be more specific, I will provide the example of my problem. I am working on creating a user-defined data type for spherical particles called 'Particle'. I want to define an operator that takes an existing array of Particle objects and adds a new Particle object to it. I was wondering how I would go about defining user defined operators to do such an action.
Currently I have, within the type definition for Particle, the following lines:
procedure, public:: addNewParticleTo
generic:: operator(.spawn.) => addNewParticleTo
Following which, I have a subroutine that is defined as follows:
subroutine addNewParticleTo(a_LHS, a_RHS)
implicit none
class(Particle), dimension(:), allocatable, intent(in):: a_LHS
class(Particle), dimension(:), allocatable, intent(inout):: a_RHS
<rest of the code>
end subroutine addNewParticleTo
I intend for the operator to be invoked as:
particle .spawn. particleArray
I was wondering if this is the correct way to go about doing this. Any suggestions or advise on this will be very helpful.
To expand on the comments, you will need to have the operator code as a function. Further, each input would need to be intent(in). This would indeed allow something like array = particle .spawn. array.
However, another change is required to your subroutine: one of your arguments should be a scalar. [The first, unless you play with the pass attribute.]
function addNewParticleTo(A, B) result(C)
class(particle), intent(in) :: A
class(particle), allocatable, intent(in) :: B(:)
class(particle), allocatable :: C(:)
! ... code to do the appending
end function
Finally, my advice is that having this as a type-bound operator is making things quite complicated, with the polymorphism and so on. Also, array = particle .spawn. array seems very unintuitive.
Instead, just a plain subroutine so that call add_to_particle_array(all_particles, new_particle) works seems cleaner. This is closer to your original code, but doesn't answer your question about operators, alas.