can anybody enlighten me why the following code is rejected by NAG Fortran, ifort and gfortran? It compiles if line 7 is commented out. What am I doing wrong?
module myclass implicit none type, abstract :: vector_class contains procedure(fun_r_v), deferred :: norm !== NAG Fortran, ifort and gfortran reject the following line == procedure(assign_v_v), deferred :: assign !== end type vector_class
abstract interface real function fun_r_v (this) import :: vector_class class(vector_class), intent(in) :: this end function fun_r_v subroutine assign_v_v (this,v) import :: vector_class class(vector_class), intent(inout) :: this class(vector_class), intent(in) :: v end subroutine assign_v_v end interface
type, extends(vector_class) :: my_vector_type real :: elements(100) contains procedure :: norm => my_norm procedure :: assign => my_assign end type my_vector_type contains real function my_norm (this) class(my_vector_type), intent(in) :: this
my_norm = sqrt (sum (this%elements(:)**2)) end function my_norm
subroutine my_assign (this,v) class(my_vector_type), intent(inout) :: this class(my_vector_type), intent(in) :: v
this%elements(:) = v%elements(:) end subroutine my_assign end module myclass
Harald Anlauf <anlauf.2...@arcor.de> wrote: > can anybody enlighten me why the following code is rejected by NAG > Fortran, ifort and gfortran? > It compiles if line 7 is commented out. What am I doing wrong?
[code mostly elided]
Well, the first thing you are doing wrong is not telling us exactly what the compiler's error message is. Yes, I know we ought to be good enough to be able to figure out what is wrong without such extra information, but there is a reason why compilers generally say more than just "nope; didn't like that; try again." :-)
I threw the code at NAG to find out that it was complaining
"Argument V of overriding type-bound procedure ASSIGN of type MY_VECTOR_TYPE has the wrong data type"
Ok. That gives me at least something to look at. Ah. I see (well, I think I do, as my actual experience with this stuff is minimal).
Your abstract type has a deferred type-bound procedure with interface
> subroutine assign_v_v (this,v) > import :: vector_class > class(vector_class), intent(inout) :: this > class(vector_class), intent(in) :: v > end subroutine assign_v_v
Your extended type is trying to override this binding with a procedure
> subroutine my_assign (this,v) > class(my_vector_type), intent(inout) :: this > class(my_vector_type), intent(in) :: v
> this%elements(:) = v%elements(:) > end subroutine my_assign
To quote from page 103 of a certain F2003 book (:-))
When overriding bindings are used in conjunction with polymorphism, the compiler might not be able to determine at compile time which specific procedure is invoked by a particular reference in the code; the same reference might invoke different procedures for different executions of it. Therefore the parent binding and the overriding one must be similar enough that the same invoking code makes sense for both bindings. The rules and restrictions to ensure that are:
... 2. They must both have the same number of dummy arguments. Dummy arguments that correspond by position must have the same names and characteristics, except that the passed-object dummy will differ in type.
Your argument V is not the passed-object dummy argument and it does not have the same characteristics as in the parent binding in your example. THIS is the passed-object dummy, so it is ok.
-- Richard Maine | Good judgment comes from experience; email: last name at domain . net | experience comes from bad judgment. domain: summertriangle | -- Mark Twain
> can anybody enlighten me why the following code is rejected by NAG > Fortran, ifort and gfortran?
I am very happy to see that you are trying out OOP with gfortran. However, I must stress that it is, as yet, highly experimental and lacks some important features.
Janus Weil and I, aided and abetted by Tobias Burnus and the usual suspects, have been going at it like a storm over the last couple of months. Unfortunately, we have just missed the 4.5.0 release with some of the most important improvements. In the next few weeks, you will see the fortran-dev branch of gcc doing the right thing. We will backport the improvements as soon as we can and they will certainly appear in 4.6.0.
Any feedback you can give us would be gratefully received.
> To quote from page 103 of a certain F2003 book (:-))
> When overriding bindings are used in conjunction with > polymorphism, the compiler might not be able to determine > at compile time which specific procedure is invoked by a > particular reference in the code; the same reference might > invoke different procedures for different executions of it. > Therefore the parent binding and the overriding one must > be similar enough that the same invoking code makes sense > for both bindings. The rules and restrictions to ensure that are:
> ... > 2. They must both have the same number of dummy arguments. > Dummy arguments that correspond by position must have > the same names and characteristics, except that the > passed-object dummy will differ in type.
> Your argument V is not the passed-object dummy argument and it does not > have the same characteristics as in the parent binding in your example. > THIS is the passed-object dummy, so it is ok.
Sorry, but I am still completely blank. How should I correctly specify the characteristics of V? I had also tried several variations before the original posting, but I did not succeed.
Harald Anlauf <anlauf.2...@arcor.de> wrote: > On Nov 7, 1:35 am, nos...@see.signature (Richard Maine) wrote: > > Harald Anlauf <anlauf.2...@arcor.de> wrote: > > Your abstract type has a deferred type-bound procedure with interface
... > > Your argument V is not the passed-object dummy argument and it does not > > have the same characteristics as in the parent binding in your example. > > THIS is the passed-object dummy, so it is ok.
> Sorry, but I am still completely blank. How should I correctly specify > the characteristics of V? I had also tried several variations before > the original posting, but I did not succeed.
It has to have the same characteristics as in the parent type. Namely, it has to be class(vector_class) rather than class(my_vector_type).
Of course, then you have to deal with that broader case. You can't just assume that it is in my_vector_type. If you want to refer to the elements component of v, you'll need to use select type to make sure that v has such a component. If you just change the declaration of v without a select type, the compiler will bitch about that (NAG did when I tried).
> Many thanks in advance for a working example.
Sorry. I haven't done enough of this to have one handy. Perhaps someone else does. When I was last seriously looking at this stuff, compilers didn't have enough of the features done to do much useful with it.
If I change your my_assign to the following, it compiles with NAG anyway, but I'm not prepared to actually test it and I haven't done enough of this to be sure it would have the desired result in all cases. I also just punted on the default case.
subroutine my_assign (this,v) class(my_vector_type), intent(inout) :: this class(vector_class), intent(in) :: v select type(v) class is (my_vector_type) this%elements(:) = v%elements(:) class default write (*,*) 'Oops' end select end subroutine my_assign
-- Richard Maine | Good judgment comes from experience; email: last name at domain . net | experience comes from bad judgment. domain: summertriangle | -- Mark Twain
Richard Maine wrote: > Harald Anlauf <anlauf.2...@arcor.de> wrote:
>> On Nov 7, 1:35 am, nos...@see.signature (Richard Maine) wrote: >>> Harald Anlauf <anlauf.2...@arcor.de> wrote: >>> Your abstract type has a deferred type-bound procedure with interface
>>>> subroutine assign_v_v (this,v) >>>> import :: vector_class >>>> class(vector_class), intent(inout) :: this >>>> class(vector_class), intent(in) :: v >>>> end subroutine assign_v_v >>> Your extended type is trying to override this binding with a procedure
>>>> subroutine my_assign (this,v) >>>> class(my_vector_type), intent(inout) :: this >>>> class(my_vector_type), intent(in) :: v >>>> this%elements(:) = v%elements(:) >>>> end subroutine my_assign > ... >>> Your argument V is not the passed-object dummy argument and it does not >>> have the same characteristics as in the parent binding in your example. >>> THIS is the passed-object dummy, so it is ok. >> Sorry, but I am still completely blank. How should I correctly specify >> the characteristics of V? I had also tried several variations before >> the original posting, but I did not succeed.
> It has to have the same characteristics as in the parent type. Namely, > it has to be class(vector_class) rather than class(my_vector_type).
> Of course, then you have to deal with that broader case. You can't just > assume that it is in my_vector_type. If you want to refer to the > elements component of v, you'll need to use select type to make sure > that v has such a component. If you just change the declaration of v > without a select type, the compiler will bitch about that (NAG did when > I tried).
>> Many thanks in advance for a working example.
> Sorry. I haven't done enough of this to have one handy. Perhaps someone > else does. When I was last seriously looking at this stuff, compilers > didn't have enough of the features done to do much useful with it.
> If I change your my_assign to the following, it compiles with NAG > anyway, but I'm not prepared to actually test it and I haven't done > enough of this to be sure it would have the desired result in all cases. > I also just punted on the default case.
> subroutine my_assign (this,v) > class(my_vector_type), intent(inout) :: this > class(vector_class), intent(in) :: v > select type(v) > class is (my_vector_type) > this%elements(:) = v%elements(:) > class default > write (*,*) 'Oops' > end select > end subroutine my_assign
OK, I'll admit I "know (absolutely) nuthink" about any of this but I'm confused why his "this" is ok but "v" isn't since in assign_v_v is
dpb <n...@non.net> wrote: > Richard Maine wrote: > > Harald Anlauf <anlauf.2...@arcor.de> wrote:
> >> On Nov 7, 1:35 am, nos...@see.signature (Richard Maine) wrote: > >>> Harald Anlauf <anlauf.2...@arcor.de> wrote: > >>> Your abstract type has a deferred type-bound procedure with interface
> >>>> subroutine assign_v_v (this,v) > >>>> import :: vector_class > >>>> class(vector_class), intent(inout) :: this > >>>> class(vector_class), intent(in) :: v > >>>> end subroutine assign_v_v > >>> Your extended type is trying to override this binding with a procedure
> >>>> subroutine my_assign (this,v) > >>>> class(my_vector_type), intent(inout) :: this > >>>> class(my_vector_type), intent(in) :: v > >>>> this%elements(:) = v%elements(:) > >>>> end subroutine my_assign > > ... > >>> Your argument V is not the passed-object dummy argument and it does not > >>> have the same characteristics as in the parent binding in your example. > >>> THIS is the passed-object dummy, so it is ok. > OK, I'll admit I "know (absolutely) nuthink" about any of this but I'm > confused why his "this" is ok but "v" isn't since in assign_v_v is
> class(vector_class), intent(inout) :: this
> while in my_assign its
> class(my_vector_type), intent(inout) :: this
> Seems to me that this doesn't agree, either???
Because this is the passed-object dummy. I personally would have preferred to make that explicit in the declaration. In fact, I had to go back and check that if you don't say anything about passed-object or not, then there is one. If the declaration had been explicit, I wouldn't have had to go look.
Ok. That's the legalistic answer - that the standard makes an exception for the passed-object dummy and this fits in the exception. I predict the next question is going to be something along the line of "Why is that an exception?"
I actually don't recall this stuff very well at all. I'm sure that's because I didn't use it enough for it to sink in deeply enough to be second nature. As a result, my comments are based on reconstruction, rather than memory. I think I have this part more or less right, though; the reconstruction seems to make sense.
Because THIS is the passed-object dummy, you won't ever end up in subroutine my_assign unless THIS is of class(my_vector_type). It being of that class is what makes my_assign be the particular procedure that gets called, so that procedure never has to deal with the possibility that THIS might be outside of that class.
The procedure will get invoked by something like (though the name is evocative of assignment, it isn't an assignment, so the reference will look like a call statement instead of an assignment statement)
call this%assign(v)
The actual names don't have to match, of course, but I made them do so for simplicity of exposition. That's how a passed-object dummy translates in subroutine call syntax; it comes from outside of what looks like the actual argument list.
-- Richard Maine | Good judgment comes from experience; email: last name at domain . net | experience comes from bad judgment. domain: summertriangle | -- Mark Twain
> Because this is the passed-object dummy. I personally would have > preferred to make that explicit in the declaration. In fact, I had to go > back and check that if you don't say anything about passed-object or > not, then there is one. If the declaration had been explicit, I wouldn't > have had to go look.
> Ok. That's the legalistic answer - that the standard makes an exception > for the passed-object dummy and this fits in the exception. I predict > the next question is going to be something along the line of "Why is > that an exception?"
... OK, that's enough to satisfy my curiosity. I don't foresee ever writing enough new Fortran in my current status that I'm going to bother to even try to slog through the oo stuff; as noted I was just reading along and the discrepancy here was enough to jog me enough to ask for the most rudimentary explanation.
(In this case, "because" would probably have been about enough; sorta' like some of my tongue-in-cheek responses on occasion :) )...
Thanks, as always you provided enough context to make it readable, Richard...
On Nov 7, 6:16 pm, nos...@see.signature (Richard Maine) wrote:
> assume that it is in my_vector_type. If you want to refer to the > elements component of v, you'll need to use select type to make sure > that v has such a component. If you just change the declaration of v > without a select type, the compiler will bitch about that (NAG did when > I tried).
OK, now I slowly begin to understand the error messages that I got.
Initially I had the wrong impression that there were some similarity to the case of generic procedures, where the compiler would know at compile time which specific procedure to select. So the new features allow only for checking the appropriateness of the actual parameters at run time, but not at compile time.
(There are many cases where it would be nice to have a verification of the compatibility of arguments already at compile time, like for the assignment in the example. This would leave less room for runtime trouble...)
> subroutine my_assign (this,v) > class(my_vector_type), intent(inout) :: this > class(vector_class), intent(in) :: v > select type(v) > class is (my_vector_type) > this%elements(:) = v%elements(:) > class default > write (*,*) 'Oops' > end select > end subroutine my_assign
Yes, this does work with NAG Fortran, ifort 11.1 and xlf 12. I take it from Paul's posting that gfortran is almost there... ;-)
(If there were a possibility to tell the compiler that the "class default" branch should never be reached, then it would be able in principle to perform the static analysis mentioned above; maybe after inlining).
Harald Anlauf <anlauf.2...@arcor.de> wrote: > (There are many cases where it would be nice to have a verification > of the compatibility of arguments already at compile time, like for > the assignment in the example. This would leave less room for runtime > trouble...)
You do get verification at compile time of those things that can be verified then. But the whole point of CLASS is that it is saying that you don't know the exact type at compile time. If you know it at compile time, you use TYPE instead of class. That doesn't work here because you are inheriting the binding from an abstract type. An abstract type can never be the exact type of something; about the only thing you can do with it is extend it to something that might not be so abstract.
-- Richard Maine | Good judgment comes from experience; email: last name at domain . net | experience comes from bad judgment. domain: summertriangle | -- Mark Twain
>> subroutine my_assign (this,v) >> class(my_vector_type), intent(inout) :: this >> class(vector_class), intent(in) :: v >> select type(v) >> class is (my_vector_type) >> this%elements(:) = v%elements(:) >> class default >> write (*,*) 'Oops' >> end select >> end subroutine my_assign
> Yes, this does work with NAG Fortran, ifort 11.1 and xlf 12. > I take it from Paul's posting that gfortran is almost there... ;-)
> (If there were a possibility to tell the compiler that the > "class default" branch should never be reached, then it would > be able in principle to perform the static analysis mentioned > above; maybe after inlining).
In fact, by saying "class is (<base type>)" you are already covering the complete inheritance tree. So you can in fact omit the class default branch because it *will* never be reached in the above case.
> In fact, by saying "class is (<base type>)" you are already > covering the complete inheritance tree. So you can in fact > omit the class default branch because it *will* never be reached > in the above case.
Ack. Sorry for stupidly misreading your code. Please disregard my previous message.
On Nov 7, 11:44 pm, Harald Anlauf <anlauf.2...@arcor.de> wrote:
> > subroutine my_assign (this,v) > > class(my_vector_type), intent(inout) :: this > > class(vector_class), intent(in) :: v > > select type(v) > > class is (my_vector_type) > > this%elements(:) = v%elements(:) > > class default > > write (*,*) 'Oops' > > end select > > end subroutine my_assign
> Yes, this does work with NAG Fortran, ifort 11.1 and xlf 12. > I take it from Paul's posting that gfortran is almost there... ;-)
Actually gfortran *is* right there now :)
Just today I committed a patch, which implements SELECT TYPE with CLASS IS, to the fortran-dev branch of GCC, and it compiles the above test case (the repaired version) without a problem.
The branch contains a couple of additional OOP features, which gfortran 4.5 trunk does not have yet (cf. http://gcc.gnu.org/wiki/OOP). Anyone brave enough to check out the branch via svn and compile it from source is welcome to try out gfortran's brand-new OOP implementation (I'll be happy to help with the technical details). But beware: These features are still young, and may certainly contain bugs. The more important it is that people test them ...
On Nov 11, 10:35 pm, Janus Weil <jaydu...@googlemail.com> wrote:
> The branch contains a couple of additional OOP features, which > gfortran 4.5 trunk does not have yet (cf.http://gcc.gnu.org/wiki/OOP). > Anyone brave enough to check out the branch via svn and compile it > from source is welcome to try out gfortran's brand-new OOP > implementation
If you are brave enough to test the fortran-dev branch, but not brave enough to build it yourself, you may want to try the binaries that Tobias Burnus generously provides at:
> There you can find x86_64 binaries of gfortran 4.5 trunk as well as > the fortran-dev branch.
The x86_64 machine at my office runs OpenSuse 11.0 and has minor problems with these builds, in particular with debugging (-g). It looks like the assembler from binutils is too old for these builds. I mailed Tobias but got no answer up to now.