Discussion:
Assignment interfaces with allocatable polymorphic variables in gfortran 5.5.0 & 8.1.0.
Ethan Beyak
2018-09-06 20:17:57 UTC
Permalink
Hi users and developers of gfortran,

I would like to assign allocatable polymorphic variables, i.e.,
class(foo_t), allocatable :: foo, from a given type, i.e., type(foo_t) ::
foo_type. I can compile this no problem with gfortran 8.1.0, but I
encounter some issues compiling when I try with gfortran 5.5.0. Here's a
simple example module and program.

PROGRAM test_public_assignment.f90
=========
program test_public_assignment
use baz_module
use iso_fortran_env
implicit none

type(vector), parameter :: d = vector(x=4, y=2, z=1)
class(vector), allocatable :: e, wrk, f

call baz(d, e)

wrk = e ! invoking foo

wrk%x = 4*e%x
wrk%y = 3*e%y
wrk%z = 2*e%z

f = wrk ! invoking foo

write(*,*) "Compiler version: ", compiler_version()
write(*,*) "Compiler options: ", compiler_options()
write(*,*) "d: ", d%x, d%y, d%z
write(*,*) "e: ", e%x, e%y, e%z
write(*,*) "f: ", f%x, f%y, f%z

end program test_public_assignment
=========

MODULE baz_module.f90
=========
module baz_module
implicit none

! gfortran 8.1 compiles, but 5.5 does not
private
public baz, vector

! work-around for gfortran 5.5, but not ideal
!public
!private foo

interface assignment (=)
module procedure foo
end interface assignment (=)

type vector
real :: x, y, z
end type vector

contains

subroutine foo(lhs, rhs)

class(vector), intent(in) :: rhs
class(vector), allocatable, intent(out) :: lhs

allocate(lhs, source=rhs)

end subroutine foo

subroutine baz(a, b)

class(vector), intent(in) :: a
class(vector), allocatable, intent(out) :: b
type(vector) :: wrk

wrk%x = 2*a%x
wrk%y = 3*a%y
wrk%z = 4*a%z

b = wrk ! invoking foo

end subroutine baz

end module baz_module
=========

For example, running on gfortran 8.1.0 gives the following output:

OUTPUT 1
=========
$ gfortran baz_module.f90 test_public_assignment.f90 -o test.out
$ ./test.out
Compiler version: GCC version 8.1.0
Compiler options: -mtune=generic -march=x86-64
d: 4.00000000 2.00000000 1.00000000
e: 8.00000000 6.00000000 4.00000000
f: 32.0000000 18.0000000 8.00000000
=========

However, on version 5.5, I get the following errors:

OUTPUT 2
=========
$ gfortran --version
GNU Fortran (Ubuntu 5.5.0-12ubuntu1) 5.5.0 20171010

$ gfortran baz_module.f90 test_public_assignment.f90 -o test.out
test_public_assignment.f90:13:0:

wrk = e ! invoking foo
1
Error: Assignment to an allocatable polymorphic variable at (1) is not yet
supported
test_public_assignment.f90:19:0:

f = wrk ! invoking foo
1
Error: Assignment to an allocatable polymorphic variable at (1) is not yet
supported
=========

Now I did find some workaround by setting the default accessibility of the
module to be public and explicitly declaring the complement of the set of
procedures and variables that I wanted to be private. I'm not sure what
gfortran 5.5.0 is doing to be honest, but the definition of the assignment
can be used in the calling program. Commenting out lines 5,6 and commenting
in lines 8,9 in baz_module.f90 gave me the following output on gfortran
5.5.0

OUTPUT 3
=========
Compiler version: GCC version 5.5.0 20171010
Compiler options: -mtune=generic -march=x86-64
d: 4.00000000 2.00000000 1.00000000
e: 8.00000000 6.00000000 4.00000000
f: 32.0000000 18.0000000 8.00000000
=========

So I have two questions for the gfortran community: 1) do you know why
inverting the module accessibility causes these assignments to work in
gfortran 5.5.0? It seems as if the assignment interface was made public
somehow, but I'm not certain. 2) can you think of any *clean* solutions to
this problem? I'd love backward compatibility while not going against the
recommended standard of private default accessibility.

I look forward to reading what you have to say. Thanks for your time.

Best,

Ethan
Janus Weil
2018-09-07 05:56:34 UTC
Permalink
Hi Ethan,
Post by Ethan Beyak
OUTPUT 2
=========
$ gfortran --version
GNU Fortran (Ubuntu 5.5.0-12ubuntu1) 5.5.0 20171010
$ gfortran baz_module.f90 test_public_assignment.f90 -o test.out
wrk = e ! invoking foo
1
Error: Assignment to an allocatable polymorphic variable at (1) is not yet
supported
Note that gfortran version 7 can also compile the program in its
original form (so you don't necessarily need version 8), but
unfortunately earlier versions fail.
Post by Ethan Beyak
Now I did find some workaround by setting the default accessibility of the
module to be public and explicitly declaring the complement of the set of
procedures and variables that I wanted to be private. I'm not sure what
gfortran 5.5.0 is doing to be honest, but the definition of the assignment
can be used in the calling program. Commenting out lines 5,6 and commenting
in lines 8,9 in baz_module.f90 gave me the following output on gfortran
5.5.0
OUTPUT 3
=========
Compiler version: GCC version 5.5.0 20171010
Compiler options: -mtune=generic -march=x86-64
d: 4.00000000 2.00000000 1.00000000
e: 8.00000000 6.00000000 4.00000000
f: 32.0000000 18.0000000 8.00000000
=========
So I have two questions for the gfortran community: 1) do you know why
inverting the module accessibility causes these assignments to work in
gfortran 5.5.0? It seems as if the assignment interface was made public
somehow, but I'm not certain.
Exactly, the "public" statement makes everything in the module public
by default. The assignment operator is private otherwise.
Post by Ethan Beyak
2) can you think of any *clean* solutions to
this problem? I'd love backward compatibility while not going against the
recommended standard of private default accessibility.
A more reasonable approach might be to not make everything public, but
just the assignment interface:

public assignment(=)

HTH,
Janus
Ethan Beyak
2018-09-07 14:36:25 UTC
Permalink
Janus,

Thank you very much for your response. I didn't realize you could put an
'assignment (=)' in a public statement. This'll solve my problem perfectly!

As a follow-up, let's say I did have multiple 'interface assignment (=)'
blocks in this module. Would the 'public assignment (=)' statement then
make all of assignments public then?
Is there any way to make these 'public assignment (=)' statements distinct?
I tried the following, both failed to compile on gfortran 5.5.0:

=======
interface assign_foo assignment (=)
module procedure foo
end interface assign_foo assignment (=)

interface assignment (=) assign_foo
module procedure foo
end interface assignment (=) assign_foo

'Error: Syntax error: Trailing garbage in INTERFACE statement'
=======

Is there any way I could apply the public attribute to the interface block
directly, or am I limited to public statements for affecting the
accessibility of interface blocks?

And a brief convention question: is it standard to omit whitespace between
'assignment' and '(=)' when writing Fortran, or is there no general
consensus?

Thanks,

Ethan
Post by Janus Weil
Hi Ethan,
Post by Ethan Beyak
OUTPUT 2
=========
$ gfortran --version
GNU Fortran (Ubuntu 5.5.0-12ubuntu1) 5.5.0 20171010
$ gfortran baz_module.f90 test_public_assignment.f90 -o test.out
wrk = e ! invoking foo
1
Error: Assignment to an allocatable polymorphic variable at (1) is not
yet
Post by Ethan Beyak
supported
Note that gfortran version 7 can also compile the program in its
original form (so you don't necessarily need version 8), but
unfortunately earlier versions fail.
Post by Ethan Beyak
Now I did find some workaround by setting the default accessibility of
the
Post by Ethan Beyak
module to be public and explicitly declaring the complement of the set of
procedures and variables that I wanted to be private. I'm not sure what
gfortran 5.5.0 is doing to be honest, but the definition of the
assignment
Post by Ethan Beyak
can be used in the calling program. Commenting out lines 5,6 and
commenting
Post by Ethan Beyak
in lines 8,9 in baz_module.f90 gave me the following output on gfortran
5.5.0
OUTPUT 3
=========
Compiler version: GCC version 5.5.0 20171010
Compiler options: -mtune=generic -march=x86-64
d: 4.00000000 2.00000000 1.00000000
e: 8.00000000 6.00000000 4.00000000
f: 32.0000000 18.0000000 8.00000000
=========
So I have two questions for the gfortran community: 1) do you know why
inverting the module accessibility causes these assignments to work in
gfortran 5.5.0? It seems as if the assignment interface was made public
somehow, but I'm not certain.
Exactly, the "public" statement makes everything in the module public
by default. The assignment operator is private otherwise.
Post by Ethan Beyak
2) can you think of any *clean* solutions to
this problem? I'd love backward compatibility while not going against the
recommended standard of private default accessibility.
A more reasonable approach might be to not make everything public, but
public assignment(=)
HTH,
Janus
Janus Weil
2018-09-07 17:20:42 UTC
Permalink
Thank you very much for your response. I didn't realize you could put an 'assignment (=)' in a public statement. This'll solve my problem perfectly!
As a follow-up, let's say I did have multiple 'interface assignment (=)' blocks in this module. Would the 'public assignment (=)' statement then make all of assignments public then?
I think so.
Is there any way I could apply the public attribute to the interface block directly, or am I limited to public statements for affecting the accessibility of interface blocks?
I'm afraid there is no syntax for specifying accessibility in the
INTERFACE statement directly. I have also been missing such a feature
occasionally.

Another thing you could do is to use a type-bound assignment operator, like so:

type vector
real :: x, y, z
contains
procedure :: foo
generic :: assignment(=) => foo
end type vector

However, this approach seems to conflict with the allocatable argument
that you are using in 'foo'. At least that's what gfortran says:

19 | procedure :: foo
| 1
Error: Passed-object dummy argument of ‘foo’ at (1) must not be ALLOCATABLE
And a brief convention question: is it standard to omit whitespace between 'assignment' and '(=)' when writing Fortran, or is there no general consensus?
You can, but you don't have to. It's a question of personal
preference. I don't think there is any 'general consensus'.

Cheers,
Janus
Post by Janus Weil
Hi Ethan,
Post by Ethan Beyak
OUTPUT 2
=========
$ gfortran --version
GNU Fortran (Ubuntu 5.5.0-12ubuntu1) 5.5.0 20171010
$ gfortran baz_module.f90 test_public_assignment.f90 -o test.out
wrk = e ! invoking foo
1
Error: Assignment to an allocatable polymorphic variable at (1) is not yet
supported
Note that gfortran version 7 can also compile the program in its
original form (so you don't necessarily need version 8), but
unfortunately earlier versions fail.
Post by Ethan Beyak
Now I did find some workaround by setting the default accessibility of the
module to be public and explicitly declaring the complement of the set of
procedures and variables that I wanted to be private. I'm not sure what
gfortran 5.5.0 is doing to be honest, but the definition of the assignment
can be used in the calling program. Commenting out lines 5,6 and commenting
in lines 8,9 in baz_module.f90 gave me the following output on gfortran
5.5.0
OUTPUT 3
=========
Compiler version: GCC version 5.5.0 20171010
Compiler options: -mtune=generic -march=x86-64
d: 4.00000000 2.00000000 1.00000000
e: 8.00000000 6.00000000 4.00000000
f: 32.0000000 18.0000000 8.00000000
=========
So I have two questions for the gfortran community: 1) do you know why
inverting the module accessibility causes these assignments to work in
gfortran 5.5.0? It seems as if the assignment interface was made public
somehow, but I'm not certain.
Exactly, the "public" statement makes everything in the module public
by default. The assignment operator is private otherwise.
Post by Ethan Beyak
2) can you think of any *clean* solutions to
this problem? I'd love backward compatibility while not going against the
recommended standard of private default accessibility.
A more reasonable approach might be to not make everything public, but
public assignment(=)
HTH,
Janus
Loading...