In a sourced allocation of an allocatable polymorphic, how is the value copied across from the source? For instance, consider this example, where bar_t is an extension of foo_t:
type(bar_t) :: b class(foo_t), allocatable :: f
allocate(f, source=b)
This will allocate f, give it a dynamic type of bar_t, and set its value equal to b. But how is this value setting done? Is it an intrinsic assignment? Or, is a defined assignment done (assuming bar_t has an ASSIGNMENT(=) type-bound procedure)?
If the former, then is it possible to set up f with b's type, but without any value setting taking place via intrinsic assignment? This would be useful, for instance, if foo_t and bar_t were linked lists -- for which intrinsic assignment is not the right thing to do.
> In a sourced allocation of an allocatable polymorphic, how is the > value copied across from the source? For instance, consider this > example, where bar_t is an extension of foo_t:
> type(bar_t) :: b > class(foo_t), allocatable :: f
> allocate(f, source=b)
> This will allocate f, give it a dynamic type of bar_t, and set its > value equal to b. But how is this value setting done? Is it an > intrinsic assignment? Or, is a defined assignment done (assuming bar_t > has an ASSIGNMENT(=) type-bound procedure)?
> If the former, then is it possible to set up f with b's type, but > without any value setting taking place via intrinsic assignment? This > would be useful, for instance, if foo_t and bar_t were linked lists -- > for which intrinsic assignment is not the right thing to do.
I believe that that it is an intrinsic assignment. EBNF has
SOURCE=source-expr
source-expr is expr expr is [ expr defined-binary-op ] level-5-expr defined-binary-op is . letter [ letter ] ... .
steve <kar...@comcast.net> wrote: > On Jan 31, 2:38 pm, Rich Townsend <mylastn...@astro.wisc.edu> wrote: > > In a sourced allocation of an allocatable polymorphic, how is the > > value copied across from the source? For instance, consider this > > example, where bar_t is an extension of foo_t:
> > type(bar_t) :: b > > class(foo_t), allocatable :: f
> > allocate(f, source=b)
> > This will allocate f, give it a dynamic type of bar_t, and set its > > value equal to b. But how is this value setting done? Is it an > > intrinsic assignment? Or, is a defined assignment done (assuming bar_t > > has an ASSIGNMENT(=) type-bound procedure)?
> > If the former, then is it possible to set up f with b's type, but > > without any value setting taking place via intrinsic assignment? This > > would be useful, for instance, if foo_t and bar_t were linked lists -- > > for which intrinsic assignment is not the right thing to do.
> I believe that that it is an intrinsic assignment. EBNF > has
> SOURCE=source-expr
> source-expr is expr > expr is [ expr defined-binary-op ] level-5-expr > defined-binary-op is . letter [ letter ] ... .
> A defined assignment is not a level-5-expr.
That's pretty much a non-sequitur. You are just talking about the syntax of the expression. The syntax is, not surprisingly, that of any other expression. That has nothing to do with what happens after the expression is evaluated. Defined assignment is not part of the expression; it is something that might happen with an expression. Heck, I could generalize your argument to say that there is no such thing as defined assignment because the syntax of assignment has the same expr on its right-hand side and "defined asignment is not a level-5-expr."
I don't actually see that the standard uses the word "assignment" at all in the context of SOURCE= in the allocate statement. It just says that "the value of allocate-object becomes that of source-expr". (And I see that f2008 has some different wording - possibly a bug fix, but the differences have to do only with array vs scalar issues; it still just talks about "values becoming.") That "value becomes" bit sounds a lot like the same thing as intrinsic assignment does for cases where the type and type parameters agree, but I'm not going to go out on a limb and say that it actually is intrinsic assignment because maybe I've missed something. I'll waffle and say that it seems to do the same thing as intrinsic assignment even if it doesn't use that name for it. I certainly see no justification at all for it being defined assignment.
Sounds to me like what you want is the MOLD= that got added in f2008. Umm. Anyway I think that is what MOLD= is supposed to do. I sure can't deduce that from the words of the standard, though. The standard appears to say nothing at all about what the MOLD= actually does. The complete and entire description of MOLD, other than just its syntax, appears to be
"If MOLD= appears and source-expr is a variable, its value need not be defined."
which I find less than edifying. Even the syntax is confused in that the restrictions talk about source-expr as though there is only one of them, even though the BNF shows source-expr in both SOURCE= and MOLD=. I'm guessing that you aren't supposed to be allowed to specify both SOURCE= and MOLD=, but I see nothing that quite says that - just words that don't make much sense if you have both of them. Well, maybe the "At most one of source-expr and type-spec shall appear" does it, though my first reading of that was just that you could not specify both source-expr and type-spec. I suppose maybe it also says that you can't specify source-expr in two different spots, but I'm sure not impressed with its clarity.
But even if I grant the syntax as ok, I'm still left completely guessing as to what the source-expr does when it is in MOLD=. All its description is in the para that begins with "If SOURCE= appears." I think someone meant paarts of that to also apply to MOLD=. You just have to figure out which parts don't make sense if the value might not be defined; that would be the bit about the "value becoming that of source-expr." I think that's a pretty good guess, but it would be nice if the standard said that instead of leaving one to guess.
-- Richard Maine | Good judgment comes from experience; email: last name at domain . net | experience comes from bad judgment. domain: summertriangle | -- Mark Twain
nos...@see.signature (Richard Maine) wrote: > steve <kar...@comcast.net> wrote:
>> On Jan 31, 2:38 pm, Rich Townsend <mylastn...@astro.wisc.edu> wrote:
>> > In a sourced allocation of an allocatable polymorphic, how is the >> > value copied across from the source? For instance, consider this >> > example, where bar_t is an extension of foo_t:
>> > type(bar_t) :: b >> > class(foo_t), allocatable :: f
>> > allocate(f, source=b)
>> > This will allocate f, give it a dynamic type of bar_t, and set its >> > value equal to b. But how is this value setting done? Is it an >> > intrinsic assignment? Or, is a defined assignment done (assuming bar_t >> > has an ASSIGNMENT(=) type-bound procedure)?
>> > If the former, then is it possible to set up f with b's type, but >> > without any value setting taking place via intrinsic assignment? This >> > would be useful, for instance, if foo_t and bar_t were linked lists -- >> > for which intrinsic assignment is not the right thing to do.
>> I believe that that it is an intrinsic assignment. EBNF >> has
>> SOURCE=source-expr
>> source-expr is expr >> expr is [ expr defined-binary-op ] level-5-expr >> defined-binary-op is . letter [ letter ] ... .
>> A defined assignment is not a level-5-expr.
> That's pretty much a non-sequitur. You are just talking about the syntax > of the expression. The syntax is, not surprisingly, that of any other > expression. That has nothing to do with what happens after the > expression is evaluated. Defined assignment is not part of the > expression; it is something that might happen with an expression. Heck, > I could generalize your argument to say that there is no such thing as > defined assignment because the syntax of assignment has the same expr on > its right-hand side and "defined asignment is not a level-5-expr."
> I don't actually see that the standard uses the word "assignment" at all > in the context of SOURCE= in the allocate statement. It just says that > "the value of allocate-object becomes that of source-expr". (And I see > that f2008 has some different wording - possibly a bug fix, but the > differences have to do only with array vs scalar issues; it still just > talks about "values becoming.") That "value becomes" bit sounds a lot > like the same thing as intrinsic assignment does for cases where the > type and type parameters agree, but I'm not going to go out on a limb > and say that it actually is intrinsic assignment because maybe I've > missed something. I'll waffle and say that it seems to do the same thing > as intrinsic assignment even if it doesn't use that name for it. I > certainly see no justification at all for it being defined assignment.
> Sounds to me like what you want is the MOLD= that got added in f2008. > Umm. Anyway I think that is what MOLD= is supposed to do. I sure can't > deduce that from the words of the standard, though. The standard appears > to say nothing at all about what the MOLD= actually does. The complete > and entire description of MOLD, other than just its syntax, appears to > be
> "If MOLD= appears and source-expr is a variable, its value need not be > defined."
> which I find less than edifying. Even the syntax is confused in that the > restrictions talk about source-expr as though there is only one of them, > even though the BNF shows source-expr in both SOURCE= and MOLD=. I'm > guessing that you aren't supposed to be allowed to specify both SOURCE= > and MOLD=, but I see nothing that quite says that - just words that > don't make much sense if you have both of them. Well, maybe the > "At most one of source-expr and type-spec shall appear" does it, though > my first reading of that was just that you could not specify both > source-expr and type-spec. I suppose maybe it also says that you can't > specify source-expr in two different spots, but I'm sure not impressed > with its clarity.
> But even if I grant the syntax as ok, I'm still left completely guessing > as to what the source-expr does when it is in MOLD=. All its description > is in the para that begins with "If SOURCE= appears." I think someone > meant paarts of that to also apply to MOLD=. You just have to figure out > which parts don't make sense if the value might not be defined; that > would be the bit about the "value becoming that of source-expr." I think > that's a pretty good guess, but it would be nice if the standard said > that instead of leaving one to guess.
Thanks for the analysis. It seems that MOLD is what I want here -- at least, going by what is written in John Reid's "The new features of Fortran 2008" document. Is the standard truly as vague as you say?
>>> On Jan 31, 2:38 pm, Rich Townsend <mylastn...@astro.wisc.edu> wrote:
>>>> In a sourced allocation of an allocatable polymorphic, how is the >>>> value copied across from the source? For instance, consider this >>>> example, where bar_t is an extension of foo_t:
>>>> type(bar_t) :: b >>>> class(foo_t), allocatable :: f
>>>> allocate(f, source=b) >>>> [...] >> Sounds to me like what you want is the MOLD= that got added in f2008. >> Umm. Anyway I think that is what MOLD= is supposed to do. I sure can't >> deduce that from the words of the standard, though. The standard appears >> to say nothing at all about what the MOLD= actually does. The complete >> and entire description of MOLD, other than just its syntax, appears to >> be
>> "If MOLD= appears and source-expr is a variable, its value need not be >> defined."
I have a related problem: suppose that there is an allocated array with polymorphic type, and I want to expand (reallocate) that array. Here is some code that realizes the task:
--- module realloc implicit none
type :: base_type integer :: i contains procedure :: assign generic :: assignment(=) => assign ! define generic assignment end type base_type
type, extends(base_type) :: extended_type integer :: j end type extended_type
contains
elemental subroutine assign (a, b) class(base_type), intent(out) :: a type(base_type), intent(in) :: b a%i = b%i end subroutine assign
subroutine reallocate (a) class(base_type), dimension(:), allocatable, intent(inout) :: a class(base_type), dimension(:), allocatable :: tmp allocate (tmp (2 * size (a))) ! how to alloc b with same type as a ? call print_type ("tmp", tmp) tmp(:size(a)) = a ! polymorphic l.h.s. call move_alloc (from=tmp, to=a) end subroutine reallocate
subroutine print_type (name, a) character(*), intent(in) :: name class(base_type), dimension(:), intent(in) :: a select type (a) type is (base_type); print *, name // " is base_type" type is (extended_type); print *, name // " is extended_type" end select end subroutine print_type
end module realloc
program main use realloc implicit none class(base_type), dimension(:), allocatable :: a
allocate (extended_type :: a(10)) call print_type ("a", a) call reallocate (a) call print_type ("a", a) end program main
---- This compiles and runs with NAG Fortran 5.2, and the output is:
a is extended_type tmp is base_type a is base_type
So the type is not preserved. To remedy this, I could write
allocate (extended_type :: tmp (2 * size (a)))
but this requires a specific 'reallocate' for each extension of base_type. A single 'reallocate' containing a 'select type' clause is not a complete solution since extensions of base_type might be defined in any module which uses module 'realloc'.
The SOURCE argument of ALLOCATE is not allowed here.
Furthermore, it looks like I need a separate specific defined assignment for each extension of base_type; there may be many such extensions. I rather would have intrinsic assignment in this situation, but this is forbidden in F2003.
My questions:
1) Is there a simpler solution in Fortran 2003?
2) Does Fortran 2008 give a solution? Apparently, it would remove the need for defined assignment. If I use MOLD, does it specify the allocate shape? Can I use allocate-shape-list together with MOLD to override this setting (cf. C633)?
>>> Sounds to me like what you want is the MOLD= that got added in f2008.
I concur with Richard.
>>> Umm. Anyway I think that is what MOLD= is supposed to do. I sure can't >>> deduce that from the words of the standard, though. The standard appears >>> to say nothing at all about what the MOLD= actually does. The complete >>> and entire description of MOLD, other than just its syntax, appears to >>> be >>> "If MOLD= appears and source-expr is a variable, its value need not be >>> defined."
I think one can deduce it from the standard, though it is not well written. My understanding is that is allocates the variable based on the effective type of the source-expr in MOLD= and "assigns" the default initializer (if existing) to it.
> subroutine reallocate (a) > class(base_type), dimension(:), allocatable, intent(inout) :: a > class(base_type), dimension(:), allocatable :: tmp > allocate (tmp (2 * size (a))) ! how to alloc b with same type as a ?
Fortran 2008: MOLD=a; Fortran 2003: SOURCE=a. The 2003 version has the disadvantage that for deeply nested derived types with allocatable components, all those are copied/initialized as well, while the MOLD= version matches allocate(effective-type-of-a :: tmp(...))
> allocate (extended_type :: tmp (2 * size (a)))
> but this requires a specific 'reallocate' for each extension of > base_type. A single 'reallocate' containing a 'select type' clause is > not a complete solution since extensions of base_type might be defined > in any module which uses module 'realloc'.
> The SOURCE argument of ALLOCATE is not allowed here.
Sorry, I do not understand this. What prevents the use of SOURCE=a?
> Furthermore, it looks like I need a separate specific defined assignment > for each extension of base_type; there may be many such extensions. I > rather would have intrinsic assignment in this situation, but this is > forbidden in F2003.
Fortran 2008 allows an intrinsic assignment, if the LHS is allocatable. Thus, for "tmp(:size(a)) = a" it would not work either - thus the intrinsic assignment does not work if one wants to resize the array.
You could use a defined assignment, defined for every type extension which adds a new component.
Otherwise, your defined assignment should work, though you could consider to use CLASS instead of TYPE for the RHS dummy argument "b".
> 2) Does Fortran 2008 give a solution? Apparently, it would remove the > need for defined assignment. If I use MOLD, does it specify the > allocate shape? Can I use allocate-shape-list together with MOLD to > override this setting (cf. C633)?
I think C633 uses an inclusive or:
"C633 (R631) If allocate-object is an array either allocate-shape-spec-list shall appear or source-expr shall appear and have the same rank as allocate-object. If allocate-object is scalar, allocate-shape-spec-list shall not appear."
"When an ALLOCATE statement is executed for an array for which allocate-shape-spec-list is specified, the values of the lower bound and upper bound expressions determine the bounds of the array. [...]" "When an ALLOCATE statement is executed for an array with no allocate-shape-spec-list, the bounds of source-expr determine the bounds of the array."
Tobias
PS: I had to use an array-free version to test with gfortran as support for polymorphic arrays is still rather incomplete [1]. Additionally, gfortran does not like [2] if a polymorphic actual is passed to a nonpolymorphic dummy; thus I had to change "assign". Afterwards using SOURCE= and using MOLD= gave always the correct effective type: "is extended_type". [1] http://gcc.gnu.org/wiki/OOP [2] http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46990 Regarding [1]: The plan was to add array support for GCC 4.6 but too many other OOP bugs/omissions had to be fixed (cf. bottom of [1]), thus fixing OOP array support has been deferred to 4.7.
> On 02/01/2011 09:21 AM, Wolfgang Kilian wrote: >>>> Sounds to me like what you want is the MOLD= that got added in f2008.
> I concur with Richard.
>>>> Umm. Anyway I think that is what MOLD= is supposed to do. I sure can't >>>> deduce that from the words of the standard, though. The standard >>>> appears >>>> to say nothing at all about what the MOLD= actually does. The complete >>>> and entire description of MOLD, other than just its syntax, appears to >>>> be >>>> "If MOLD= appears and source-expr is a variable, its value need not be >>>> defined."
> I think one can deduce it from the standard, though it is not well > written. My understanding is that is allocates the variable based on the > effective type of the source-expr in MOLD= and "assigns" the default > initializer (if existing) to it.
>> subroutine reallocate (a) >> class(base_type), dimension(:), allocatable, intent(inout) :: a >> class(base_type), dimension(:), allocatable :: tmp >> allocate (tmp (2 * size (a))) ! how to alloc b with same type as a ?
> Fortran 2008: MOLD=a; Fortran 2003: SOURCE=a. > The 2003 version has the disadvantage that for deeply nested derived > types with allocatable components, all those are copied/initialized as > well, while the MOLD= version matches > allocate(effective-type-of-a :: tmp(...))
>> allocate (extended_type :: tmp (2 * size (a)))
>> but this requires a specific 'reallocate' for each extension of >> base_type. A single 'reallocate' containing a 'select type' clause is >> not a complete solution since extensions of base_type might be defined >> in any module which uses module 'realloc'.
>> The SOURCE argument of ALLOCATE is not allowed here. > Sorry, I do not understand this. What prevents the use of SOURCE=a?
Oops -- if it was allowed, there would be no problem at all (and no need for MOLD or defined assignment). Actually, NAG accepts
and both tmp and a get the correct dynamic type. This is what I wanted to do in the first place, I just didn't dare ...
However, is this really standard-conforming? The F2003 draft, p.112 l.7 says
If SOURCE= appears, source-expr shall be conformable (2.4.5) with allocation.
My understanding is that a and tmp are not conformable if I double the size. Maybe this is a misinterpretation? However, is it obvious where the source is to be copied in the enlarged array? Will the remaining part be default-initialized correctly? What if the allocated size is smaller than a?
-- Wolfgang -- E-mail: firstnameinitial.lastn...@domain.de Domain: yahoo
> and both tmp and a get the correct dynamic type. This is what I wanted > to do in the first place, I just didn't dare ...
> However, is this really standard-conforming? The F2003 draft, p.112 l.7 > says
> If SOURCE= appears, source-expr shall be conformable (2.4.5) with > allocation.
Note added: When I turn on bounds checking in nagfor, I get a runtime error. This is what I expected. I don't think this use of SOURCE can possibly be conforming ...
> On 02/01/2011 09:21 AM, Wolfgang Kilian wrote: >>>> Sounds to me like what you want is the MOLD= that got added in f2008.
> You could use a defined assignment, defined for every type extension > which adds a new component.
> Otherwise, your defined assignment should work, though you could > consider to use CLASS instead of TYPE for the RHS dummy argument "b".
That was my first attempt, but it didn't work (NAG didn't accept it), once I wrote specifics for both base_type and extended_type. I guess because the specific procedures for the generic assignment can't be distinguished unambiguously.