- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I've recently been getting into Fortran's OO capabilities (chiefly the ones in the F2003 standard). In particular, I've been using infinite polymorphism in my code, but I've found a limitation I can't find an elegant solution to. For example, if I have the following (redacted) code in a module,
interface assignment(=)
procedure :: scalar_proc
procedure :: vector_proc
end interface
contains
subroutine scalar_proc(s, a)
class(*) :: s
type(some_type) :: a
..... set s to some scalar component of a....
end subroutine
subroutine vector_proc(v, b)
class(*) :: v(:)
type(some_type) :: b
..... set s to some vector component of a....
end subroutine
I find that the compiler regards this as an ambiguous interface. However, if I use intrinsic or derived types instead of "class(*)", the compiler has no issues. Thus, I'm worried that my only way around this is to write a separate routine for each combination of input data type AND rank. Is there a better way than that?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I would not be as trusting of the Intel compiler as you are here - sometimes we get it wrong too. A version older than 14 might get this wrong. (This is why it REALLY helps if, when describing a potential compiler bug, you tell us exactly which version you're using!)
The rule about distinguishing dummy arguments in a generic interface is this:
- they are both data objects or known to be functions, and neither is TKR compatible with the other,
...
A dummy argument is type, kind, and rank compatible, or TKR compatible, with another dummy argument if the first is type compatible with the second, the kind type parameters of the first have the same values as the corresponding kind type parameters of the second, and both have the same rank or either is assumed-rank.
s and v are type and kind compatible, because they are class(*), but they don't have the same rank (and aren't assumed-rank, a F2015 concept), so they are not TKR compatible and thus are distinguishable.
Now it gets a bit more complicated with defined assignment, which is where gfortran might be having trouble. Quoting from the F2015 draft here:
4 2 A subroutine defines the defined assignment x1 = x2 if
5 (1) the subroutine is specified with a SUBROUTINE (12.6.2.3) or ENTRY (12.6.2.6) statement that specifies
6 two dummy arguments, d1 and d2,
7 (2) either
8 (a) a generic interface (12.4.3.2) provides the subroutine with a generic-spec of ASSIGNMENT (=),
9 or
10 (b) there is a generic binding (4.5.5) in the declared type of x1 or x2 with a generic-spec of
11 ASSIGNMENT (=) and there is a corresponding binding to the subroutine in the dynamic
12 type of x1 or x2, respectively,
13 (3) the types of d1 and d2 are compatible with the dynamic types of x1 and x2, respectively,
14 (4) the type parameters, if any, of d1 and d2 match the corresponding type parameters of x1 and x2,
15 respectively, and
16 (5) either
17 (a) the ranks of x1 and x2 match those of d1 and d2 or
18 (b) the subroutine is elemental, x1 and x2 are conformable, and there is no other subroutine that
19 defines the assignment.
With intrinsic assignment, you can say array=scalar, but with defined assignment, this only works if you have a subroutine that has an array of the proper rank for the first argument and a scalar for the second, or if not that, the subroutine is ELEMENTAL. I could imagine a compiler getting tripped up on this and thinking these two procedures were ambiguous when they're not. (And even if the scalar version were elemental it would still not be ambiguous!)
I will send this example to one of the gfortran developers I know to see what he thinks.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I can't reproduce the problem with a test based on your "redacted" snippet. Please post an actual, compilable source that shows the problem.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi, Steve,
Yes, I was being lazy when I wrote my question. I've attached a file that demonstrates the "problem", if it is one. When I try to compile it, the compiler complains that the 'vector_assign' and 'scalar_assign' procedures ambiguous for the generic assignment operator.
I think what I'm trying to do is simply ill-conceived, though. I have to accept that I need to write separate procedures for each combination of scalar or vector with integer, real, logical, character, or whatever derived type I choose. I had hoped for some way to pair that down.
Thanks,
Brian
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This compiles successfully for me as well, from versions 14-17. Please show me the result of compiling this source with the -logo switch.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi, Steve,
I'm on the road for the next week or so, and I don't have access to the Intel compiler that the group I'm working with part-time has. However, I do believe the version they're using is older than 14.
On my machine, I only have gfortran 6.2. I tried it with that compiler, and it bombs out, too, with this message:
test.f90:12:33:
generic :: assignment(=) => scalar_assign, vector_assign
1
Error: ‘scalar_assign’ and ‘vector_assign’ for GENERIC ‘=’ at (1) are ambiguous
Of course, GNU is generally behind Intel, so this may not be surprising. Since you're able to compile it, I think that tells me what I most wanted to know: whether this is allowed in the standard.
Thanks,
Brian
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I would not be as trusting of the Intel compiler as you are here - sometimes we get it wrong too. A version older than 14 might get this wrong. (This is why it REALLY helps if, when describing a potential compiler bug, you tell us exactly which version you're using!)
The rule about distinguishing dummy arguments in a generic interface is this:
- they are both data objects or known to be functions, and neither is TKR compatible with the other,
...
A dummy argument is type, kind, and rank compatible, or TKR compatible, with another dummy argument if the first is type compatible with the second, the kind type parameters of the first have the same values as the corresponding kind type parameters of the second, and both have the same rank or either is assumed-rank.
s and v are type and kind compatible, because they are class(*), but they don't have the same rank (and aren't assumed-rank, a F2015 concept), so they are not TKR compatible and thus are distinguishable.
Now it gets a bit more complicated with defined assignment, which is where gfortran might be having trouble. Quoting from the F2015 draft here:
4 2 A subroutine defines the defined assignment x1 = x2 if
5 (1) the subroutine is specified with a SUBROUTINE (12.6.2.3) or ENTRY (12.6.2.6) statement that specifies
6 two dummy arguments, d1 and d2,
7 (2) either
8 (a) a generic interface (12.4.3.2) provides the subroutine with a generic-spec of ASSIGNMENT (=),
9 or
10 (b) there is a generic binding (4.5.5) in the declared type of x1 or x2 with a generic-spec of
11 ASSIGNMENT (=) and there is a corresponding binding to the subroutine in the dynamic
12 type of x1 or x2, respectively,
13 (3) the types of d1 and d2 are compatible with the dynamic types of x1 and x2, respectively,
14 (4) the type parameters, if any, of d1 and d2 match the corresponding type parameters of x1 and x2,
15 respectively, and
16 (5) either
17 (a) the ranks of x1 and x2 match those of d1 and d2 or
18 (b) the subroutine is elemental, x1 and x2 are conformable, and there is no other subroutine that
19 defines the assignment.
With intrinsic assignment, you can say array=scalar, but with defined assignment, this only works if you have a subroutine that has an array of the proper rank for the first argument and a scalar for the second, or if not that, the subroutine is ELEMENTAL. I could imagine a compiler getting tripped up on this and thinking these two procedures were ambiguous when they're not. (And even if the scalar version were elemental it would still not be ambiguous!)
I will send this example to one of the gfortran developers I know to see what he thinks.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I filled in the source with a program that uses the assignments. Seems to work fine.
module test implicit none type my_type class(*), allocatable :: scal class(*), allocatable :: vec(:) contains procedure, pass(m) :: scalar_assign procedure, pass(m) :: vector_assign generic :: assignment(=) => scalar_assign, vector_assign end type contains subroutine scalar_assign(s, m) class(*), allocatable, intent(out) :: s class(my_type), intent(in) :: m integer :: i allocate(s, source=m%scal) end subroutine subroutine vector_assign(v, m) class(*), allocatable, intent(out) :: v(:) class(my_type), intent(in) :: m allocate(v, source=m%vec) end subroutine end module test program U702749 use test implicit none class(*), allocatable :: anyscalar class(*), allocatable :: anyarray(:) type(my_type) :: mt allocate (mt%scal,source=1) allocate (mt%vec(3),source=[2.,3.,4.]) anyscalar = mt anyarray = mt select type (anyscalar) type is (integer) print *, "Correct type for anyscalar, 1=",anyscalar class default print *, "Unknown type for anyscalar" end select select type (anyarray) type is (real) print *, "Correct type for anyarray, 2. 3. 4. =",anyarray class default print *, "Unknown type for anyarray" end select end program U702749
C:\Projects>U702749.exe Correct type for anyscalar, 1= 1 Correct type for anyarray, 2. 3. 4. = 2.000000 3.000000 4.000000
I did send this to a gfortran developer for his comments.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page