Assignment interfaces with allocatable polymorphic variables in gfortran 5.5.0 & 8.1.0.

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Assignment interfaces with allocatable polymorphic variables in gfortran 5.5.0 & 8.1.0.

Ethan Beyak
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
Reply | Threaded
Open this post in threaded view
|

Re: Assignment interfaces with allocatable polymorphic variables in gfortran 5.5.0 & 8.1.0.

Janus Weil-3
Hi Ethan,

> 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:

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.


> 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.


> 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
Reply | Threaded
Open this post in threaded view
|

Re: Assignment interfaces with allocatable polymorphic variables in gfortran 5.5.0 & 8.1.0.

Ethan Beyak
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

On Fri, Sep 7, 2018 at 5:56 AM Janus Weil <[hidden email]> wrote:

> Hi Ethan,
>
> > 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:
>
> 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.
>
>
> > 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.
>
>
> > 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
>
Reply | Threaded
Open this post in threaded view
|

Re: Assignment interfaces with allocatable polymorphic variables in gfortran 5.5.0 & 8.1.0.

Janus Weil-3
Am Fr., 7. Sep. 2018 um 16:36 Uhr schrieb Ethan Beyak <[hidden email]>:
> 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



> On Fri, Sep 7, 2018 at 5:56 AM Janus Weil <[hidden email]> wrote:
>>
>> Hi Ethan,
>>
>> > 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:
>>
>> 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.
>>
>>
>> > 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.
>>
>>
>> > 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