Derived Type Allocatable Component

  • Follow


Hi,

If I have a sequence derived type with say two allocatable components, 
does it matter the order that I allocate the components?  Is it 
essentially "undefined" until I allocate the final component?
0
Reply garylscott (1357) 3/25/2012 4:16:21 PM

Gary L. Scott <garylscott@sbcglobal.net> wrote:

> If I have a sequence derived type with say two allocatable components,
> does it matter the order that I allocate the components?

No.

>  Is it 
> essentially "undefined" until I allocate the final component?

Hmm. That's a slightly subtle point, which drove me to check some
details. I'm not sure the standard is 100% consistent on this, though I
didn't spend enough time to be sure of that. The standard does say that
a derived type object is defined if each non-pointer component is
defined. An allocatable is not a pointer (its implementation in memory
might look like one, but that's irrelevant). An unallocated allocatable
is undefined. Thus, that would support your statement above that the
derived-type object is undefined as long as either of the allocatable
components are unallocated.

But you can do intrinsic assignment of a derived type object that has
unallocated components. The standard explicitly describes what happens
in that case (and it is the "obvious" thing - that the variable assigned
to will end up with the corresponding component unallocated).

Hmm. Gotta go. I think I might recall that the requirement fo rthe RHS
of an assignment be defined might not apply to derived types, but I
don't have time to check that. Breakfast call from wife.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 3/25/2012 4:37:15 PM


On 3/25/2012 11:37 AM, Richard Maine wrote:
> Gary L. Scott<garylscott@sbcglobal.net>  wrote:
>
>> If I have a sequence derived type with say two allocatable components,
>> does it matter the order that I allocate the components?
>
> No.
>
>>   Is it
>> essentially "undefined" until I allocate the final component?

I was wondering because I wanted to use the first two static components 
to read a file and assign to them "record type" and number of elements 
to be allocated.  I guess I should read into static variables and not 
make assignment to the DT until after the allocation is complete.  (just 
trying to reduce # of local variables).

>
> Hmm. That's a slightly subtle point, which drove me to check some
> details. I'm not sure the standard is 100% consistent on this, though I
> didn't spend enough time to be sure of that. The standard does say that
> a derived type object is defined if each non-pointer component is
> defined. An allocatable is not a pointer (its implementation in memory
> might look like one, but that's irrelevant). An unallocated allocatable
> is undefined. Thus, that would support your statement above that the
> derived-type object is undefined as long as either of the allocatable
> components are unallocated.
>
> But you can do intrinsic assignment of a derived type object that has
> unallocated components. The standard explicitly describes what happens
> in that case (and it is the "obvious" thing - that the variable assigned
> to will end up with the corresponding component unallocated).
>
> Hmm. Gotta go. I think I might recall that the requirement fo rthe RHS
> of an assignment be defined might not apply to derived types, but I
> don't have time to check that. Breakfast call from wife.
>

0
Reply garylscott (1357) 3/25/2012 7:13:14 PM

On 3/25/2012 2:13 PM, Gary Scott wrote:
> On 3/25/2012 11:37 AM, Richard Maine wrote:
>> Gary L. Scott<garylscott@sbcglobal.net> wrote:
>>
>>> If I have a sequence derived type with say two allocatable components,
>>> does it matter the order that I allocate the components?
>>
>> No.
>>
>>> Is it
>>> essentially "undefined" until I allocate the final component?
>
> I was wondering because I wanted to use the first two static components
> to read a file and assign to them "record type" and number of elements
> to be allocated. I guess I should read into static variables and not
> make assignment to the DT until after the allocation is complete. (just
> trying to reduce # of local variables).

It actually appears to be working as designed though...

>
>>
>> Hmm. That's a slightly subtle point, which drove me to check some
>> details. I'm not sure the standard is 100% consistent on this, though I
>> didn't spend enough time to be sure of that. The standard does say that
>> a derived type object is defined if each non-pointer component is
>> defined. An allocatable is not a pointer (its implementation in memory
>> might look like one, but that's irrelevant). An unallocated allocatable
>> is undefined. Thus, that would support your statement above that the
>> derived-type object is undefined as long as either of the allocatable
>> components are unallocated.
>>
>> But you can do intrinsic assignment of a derived type object that has
>> unallocated components. The standard explicitly describes what happens
>> in that case (and it is the "obvious" thing - that the variable assigned
>> to will end up with the corresponding component unallocated).
>>
>> Hmm. Gotta go. I think I might recall that the requirement fo rthe RHS
>> of an assignment be defined might not apply to derived types, but I
>> don't have time to check that. Breakfast call from wife.
>>
>

0
Reply garylscott (1357) 3/25/2012 7:14:47 PM

On 3/25/2012 2:14 PM, Gary Scott wrote:
> On 3/25/2012 2:13 PM, Gary Scott wrote:
>> On 3/25/2012 11:37 AM, Richard Maine wrote:
>>> Gary L. Scott<garylscott@sbcglobal.net> wrote:
>>>
>>>> If I have a sequence derived type with say two allocatable components,
>>>> does it matter the order that I allocate the components?
>>>
>>> No.
>>>
>>>> Is it
>>>> essentially "undefined" until I allocate the final component?
>>
>> I was wondering because I wanted to use the first two static components
>> to read a file and assign to them "record type" and number of elements
>> to be allocated. I guess I should read into static variables and not
>> make assignment to the DT until after the allocation is complete. (just
>> trying to reduce # of local variables).
>
> It actually appears to be working as designed though...

except for:

Error	1	 error #7822: Variables containing ultimate allocatable array 
components are forbidden from appearing directly in input/output lists.

Why this restriction if I have previously fully allocated all components 
to match the file content?	


>
>>
>>>
>>> Hmm. That's a slightly subtle point, which drove me to check some
>>> details. I'm not sure the standard is 100% consistent on this, though I
>>> didn't spend enough time to be sure of that. The standard does say that
>>> a derived type object is defined if each non-pointer component is
>>> defined. An allocatable is not a pointer (its implementation in memory
>>> might look like one, but that's irrelevant). An unallocated allocatable
>>> is undefined. Thus, that would support your statement above that the
>>> derived-type object is undefined as long as either of the allocatable
>>> components are unallocated.
>>>
>>> But you can do intrinsic assignment of a derived type object that has
>>> unallocated components. The standard explicitly describes what happens
>>> in that case (and it is the "obvious" thing - that the variable assigned
>>> to will end up with the corresponding component unallocated).
>>>
>>> Hmm. Gotta go. I think I might recall that the requirement fo rthe RHS
>>> of an assignment be defined might not apply to derived types, but I
>>> don't have time to check that. Breakfast call from wife.
>>>
>>
>

0
Reply garylscott (1357) 3/25/2012 8:33:22 PM

>>
>> It actually appears to be working as designed though...
>
> except for:
>
> Error 1 error #7822: Variables containing ultimate allocatable array
> components are forbidden from appearing directly in input/output lists.
>
> Why this restriction if I have previously fully allocated all components
> to match the file content?

Further testing:  So it appears that I can list each component 
individually in the I/O statement, just not as a single object.  Does 
that make sense?  At least it appears that I don't have to massively 
redesign...
0
Reply garylscott (1357) 3/25/2012 8:48:12 PM

Gary Scott <garylscott@sbcglobal.net> wrote:

> >>
> >> It actually appears to be working as designed though...
> >
> > except for:
> >
> > Error 1 error #7822: Variables containing ultimate allocatable array
> > components are forbidden from appearing directly in input/output lists.
> >
> > Why this restriction if I have previously fully allocated all components
> > to match the file content?
> 
> Further testing:  So it appears that I can list each component 
> individually in the I/O statement, just not as a single object.  Does
> that make sense?  At least it appears that I don't have to massively 
> redesign...

Yes, you can do it that way. As for why the prohibition, I'd point to
exactly the distinction between reading the whole derived-type object
versus reading the individual components.

When you read the whole derived-type object directly, what you are
reading would *INCLUDE* the allocation size, at least it would include
that if it were allowed. The allocation status is part of the value
object, so that would be part of what was read. When you read a single
allocatable component, however, you are reading into the contents of
that component, just as if you were reading into an allocatable array
that wasn't a component.

Consider the parallel to what happens for an INTENT(OUT) dummy argument.
If it has an allocatable component, that component gets deallocated on
entry. You can't allocate the component in the calling routine and
expect that allocation to stick in spite of the INTENT(OUT). Again,
that's because the allocation status of allocatable components is part
of the value of the object.

Reading a variable is much like passing it as an actual argument to an
intent(out) dummy. The value is completely determined by whatever is
defined from the file or the subroutine. It doesn't keep parts that
might have been defined before the read or call.

When you directly read an allocated allocatable variable, that's
different because what you are really reading is into the contents, much
like if it were a pointer and you were reading into the target. (In
fact, yes, you can also read into an allocated pointer and that's what
happens; you are reading into the target).

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 3/25/2012 9:34:20 PM

Richard Maine <nospam@see.signature> wrote:
> Gary Scott <garylscott@sbcglobal.net> wrote:

(snip)
>> > Error 1 error #7822: Variables containing ultimate allocatable array
>> > components are forbidden from appearing directly in input/output 
>> > lists.

>> > Why this restriction if I have previously fully allocated 
>> > all components to match the file content?
 
>> Further testing:  So it appears that I can list each component 
>> individually in the I/O statement, just not as a single object.  Does
>> that make sense?  At least it appears that I don't have to massively 
>> redesign...

> Yes, you can do it that way. As for why the prohibition, I'd point to
> exactly the distinction between reading the whole derived-type object
> versus reading the individual components.

> When you read the whole derived-type object directly, what you are
> reading would *INCLUDE* the allocation size, at least it would include
> that if it were allowed. The allocation status is part of the value
> object, so that would be part of what was read. When you read a single
> allocatable component, however, you are reading into the contents of
> that component, just as if you were reading into an allocatable array
> that wasn't a component.

I might believe that in the case of UNFORMATTED, but it is less
convincing in the FORMATTED case. 

For UNFORMATTED, one might say that the internal representation
includes things like allocation status and size, and that those
should also be read in. That is less obvious for FORMATTED, though.

> Consider the parallel to what happens for an INTENT(OUT) dummy argument.
> If it has an allocatable component, that component gets deallocated on
> entry. You can't allocate the component in the calling routine and
> expect that allocation to stick in spite of the INTENT(OUT). Again,
> that's because the allocation status of allocatable components is part
> of the value of the object.

> Reading a variable is much like passing it as an actual argument to an
> intent(out) dummy. The value is completely determined by whatever is
> defined from the file or the subroutine. It doesn't keep parts that
> might have been defined before the read or call.

The claim above is for I/O lists, and would also seem to include WRITE.

Now, it might be that someone wants to reserve these for future
definition such that the would work. That is, that one could write
out allocatable data, including the allocation status and size,
and later read it back in again. (Most likely as UNFORMATTED.)
If that is the reason, then I probably agree with disallowing
it for now. Otherwise, it would seem that the obvious way of
doing it, the way the OP expected, isn't so bad.

> When you directly read an allocated allocatable variable, that's
> different because what you are really reading is into the contents, much
> like if it were a pointer and you were reading into the target. (In
> fact, yes, you can also read into an allocated pointer and that's what
> happens; you are reading into the target).

-- glen
0
Reply gah (12253) 3/26/2012 12:17:38 AM

Hi Gary

Objects of derived type containing allocatable components can't appear in 
built-in I/O regardless of definition status.  As you found out, you can 
just write the individual components instead of the containing structure. 
If your compiler supports user-defined derived type I/O, you can specify 
your own routine that will be called to do the write operation.  Your 
routine will most likely have to check the allocation status of each 
allocatable component before writing it and also decide what to write if the 
component is not allocated.  Look up the write(formatted) and 
write(unformatted) generic interfaces for more information.

Richard has already answered about the reasons for this constraint.

Regards

Rafik
Visit the Fortran Cafe at http://ibm.com/rational/cafe

"Gary Scott" <garylscott@sbcglobal.net> wrote in message 
news:jknveh$af1$1@dont-email.me...
> On 3/25/2012 2:14 PM, Gary Scott wrote:
>> On 3/25/2012 2:13 PM, Gary Scott wrote:
>>> On 3/25/2012 11:37 AM, Richard Maine wrote:
>>>> Gary L. Scott<garylscott@sbcglobal.net> wrote:
>>>>
>>>>> If I have a sequence derived type with say two allocatable components,
>>>>> does it matter the order that I allocate the components?
>>>>
>>>> No.
>>>>
>>>>> Is it
>>>>> essentially "undefined" until I allocate the final component?
>>>
>>> I was wondering because I wanted to use the first two static components
>>> to read a file and assign to them "record type" and number of elements
>>> to be allocated. I guess I should read into static variables and not
>>> make assignment to the DT until after the allocation is complete. (just
>>> trying to reduce # of local variables).
>>
>> It actually appears to be working as designed though...
>
> except for:
>
> Error 1 error #7822: Variables containing ultimate allocatable array 
> components are forbidden from appearing directly in input/output lists.
>
> Why this restriction if I have previously fully allocated all components 
> to match the file content?
>
>>
>>>
>>>>
>>>> Hmm. That's a slightly subtle point, which drove me to check some
>>>> details. I'm not sure the standard is 100% consistent on this, though I
>>>> didn't spend enough time to be sure of that. The standard does say that
>>>> a derived type object is defined if each non-pointer component is
>>>> defined. An allocatable is not a pointer (its implementation in memory
>>>> might look like one, but that's irrelevant). An unallocated allocatable
>>>> is undefined. Thus, that would support your statement above that the
>>>> derived-type object is undefined as long as either of the allocatable
>>>> components are unallocated.
>>>>
>>>> But you can do intrinsic assignment of a derived type object that has
>>>> unallocated components. The standard explicitly describes what happens
>>>> in that case (and it is the "obvious" thing - that the variable 
>>>> assigned
>>>> to will end up with the corresponding component unallocated).
>>>>
>>>> Hmm. Gotta go. I think I might recall that the requirement fo rthe RHS
>>>> of an assignment be defined might not apply to derived types, but I
>>>> don't have time to check that. Breakfast call from wife.
>>>>
>>>
>>
> 


0
Reply nospam95 (822) 3/26/2012 2:00:20 AM

On 3/25/2012 4:34 PM, Richard Maine wrote:
> Gary Scott<garylscott@sbcglobal.net>  wrote:
>
>>>>
>>>> It actually appears to be working as designed though...
>>>
>>> except for:
>>>
>>> Error 1 error #7822: Variables containing ultimate allocatable array
>>> components are forbidden from appearing directly in input/output lists.
>>>
>>> Why this restriction if I have previously fully allocated all components
>>> to match the file content?
>>
>> Further testing:  So it appears that I can list each component
>> individually in the I/O statement, just not as a single object.  Does
>> that make sense?  At least it appears that I don't have to massively
>> redesign...
>
> Yes, you can do it that way. As for why the prohibition, I'd point to
> exactly the distinction between reading the whole derived-type object
> versus reading the individual components.
>
> When you read the whole derived-type object directly, what you are
> reading would *INCLUDE* the allocation size, at least it would include
> that if it were allowed. The allocation status is part of the value
> object, so that would be part of what was read. When you read a single
> allocatable component, however, you are reading into the contents of
> that component, just as if you were reading into an allocatable array
> that wasn't a component.
>
> Consider the parallel to what happens for an INTENT(OUT) dummy argument.
> If it has an allocatable component, that component gets deallocated on
> entry. You can't allocate the component in the calling routine and
> expect that allocation to stick in spite of the INTENT(OUT). Again,
> that's because the allocation status of allocatable components is part
> of the value of the object.
>
> Reading a variable is much like passing it as an actual argument to an
> intent(out) dummy. The value is completely determined by whatever is
> defined from the file or the subroutine. It doesn't keep parts that
> might have been defined before the read or call.
>
> When you directly read an allocated allocatable variable, that's
> different because what you are really reading is into the contents, much
> like if it were a pointer and you were reading into the target. (In
> fact, yes, you can also read into an allocated pointer and that's what
> happens; you are reading into the target).
>
Since it may be ambiguous as to what you might want to do in the single 
object case, perhaps we could add some sort of syntax modifier (future 
standard) that would tell the compiler that you want to treat it as if 
you specified the individual components without out having to write the 
multiple (possibly a great many) components out explicitly.  It would be 
nice to be able to do it automatically (including the allocation size) 
but I'd rather not be forced to write out huge numbers of components by 
name in those cases where it isn't necessary (where I've done the work 
to pre-allocate to the correct size).
0
Reply garylscott (1357) 3/26/2012 2:00:34 AM

For some reason, I thought you were trying to write.  The reply applies to 
read as well, except the generic interfaces are read(formatted) and 
read(unformatted).

Regards

Rafik
Visit the Fortran Cafe at http://ibm.com/rational/cafe


0
Reply nospam95 (822) 3/26/2012 2:04:51 AM

On Mar 25, 9:16=A0am, "Gary L. Scott" <garylsc...@sbcglobal.net> wrote:
> Hi,
>
> If I have a sequence derived type with say two allocatable components,
> does it matter the order that I allocate the components? =A0Is it
> essentially "undefined" until I allocate the final component?

An interesting feature of allocatable components is
that circular definitions are allowed.  If the type
of a variable includes an allocatable component and
that component has a circular definition that does
not involve pointers, the variable cannot become
defined.

Robert Corbett
0
Reply robert.corbett (96) 3/26/2012 2:16:44 AM

Gary Scott <garylscott@sbcglobal.net> wrote:
>>>> Error 1 error #7822: Variables containing ultimate allocatable array
>>>> components are forbidden from appearing directly in input/output lists.

(snip)

> Since it may be ambiguous as to what you might want to do in the single 
> object case, perhaps we could add some sort of syntax modifier (future 
> standard) that would tell the compiler that you want to treat it as if 
> you specified the individual components without out having to write the 
> multiple (possibly a great many) components out explicitly.  It would be 
> nice to be able to do it automatically (including the allocation size) 
> but I'd rather not be forced to write out huge numbers of components by 
> name in those cases where it isn't necessary (where I've done the work 
> to pre-allocate to the correct size).

Especially in the case of list-directed I/O that you might do
when debugging. The whole advantage of list-directed is that you
don't need to write so much to use it. I suppose I wouldn't mind
having the size also printed.

-- glen
0
Reply gah (12253) 3/26/2012 2:27:29 AM

Hi

Regarding formatted I/O with objects containing allocatable components:

Allocatables are usually represented using descriptors.  A Fortran 
descriptor typically contains the address of the data, allocation status, 
rank and bounds information (if applicable), and many other vendor-specific 
fields.  Technically, all fields are vendor-specific since the standard does 
not describe or mandate Fortran descriptors, but I'd be surprised if a 
vendor didn't have the ones above.  The upcoming Technical Specification for 
further interoperability with C will specify a "C descriptor" format which 
is basically a standard way of describing parts of the Fortran descriptor.

So given this, if you have formatted I/O like this:

type dt
  real, allocatable :: a(:)
  real, allocatable :: b(:)
end type
type(dt) :: x
!...
print *, x

What should the output be if x%a is unallocated?  What should it be if both 
x%a and x%b are unallocated?  If the answer is that we should write nothing 
for unallocated allocatable components, then we'll have problems with READ. 
If the answer is to write something like "(unallocated)", people will be 
unhappy that their formatted data reports contain text about implementation 
details.

On input, if we get 20 comma-separated real values on one line, how do we 
know how many of these values are part of x%a and how many are part of x%b? 
If x%a and x%b were not allocatable, we can tell by looking at the declared 
type.  But since they're allocatable, the extent can be anything.  As 
Richard explained, if you have "READ *, x", x%a and x%b will be unallocated 
(and if applicable finalized) before the read just like they are with 
INTENT(OUT) args.  So all this information has to be discernable from the 
declared type or the data file we're reading from.

The standard solves this by offloading these decisions to the user.  If a 
type has allocatable or pointer components, objects of that type can't 
appear in an I/O list unless the type has a user-defined derived type I/O 
routine.  That way, users can write output routines that write things in a 
format that can be read by their input routines, if they wish.

Regards

Rafik
Visit the Fortran Cafe at http://ibm.com/rational/cafe/

"glen herrmannsfeldt" <gah@ugcs.caltech.edu> wrote in message 
news:jkocj2$n62$1@speranza.aioe.org...
> Richard Maine <nospam@see.signature> wrote:
>> Gary Scott <garylscott@sbcglobal.net> wrote:
>
> (snip)
>>> > Error 1 error #7822: Variables containing ultimate allocatable array
>>> > components are forbidden from appearing directly in input/output
>>> > lists.
>
>>> > Why this restriction if I have previously fully allocated
>>> > all components to match the file content?
>
>>> Further testing:  So it appears that I can list each component
>>> individually in the I/O statement, just not as a single object.  Does
>>> that make sense?  At least it appears that I don't have to massively
>>> redesign...
>
>> Yes, you can do it that way. As for why the prohibition, I'd point to
>> exactly the distinction between reading the whole derived-type object
>> versus reading the individual components.
>
>> When you read the whole derived-type object directly, what you are
>> reading would *INCLUDE* the allocation size, at least it would include
>> that if it were allowed. The allocation status is part of the value
>> object, so that would be part of what was read. When you read a single
>> allocatable component, however, you are reading into the contents of
>> that component, just as if you were reading into an allocatable array
>> that wasn't a component.
>
> I might believe that in the case of UNFORMATTED, but it is less
> convincing in the FORMATTED case.
>
> For UNFORMATTED, one might say that the internal representation
> includes things like allocation status and size, and that those
> should also be read in. That is less obvious for FORMATTED, though.
>
>> Consider the parallel to what happens for an INTENT(OUT) dummy argument.
>> If it has an allocatable component, that component gets deallocated on
>> entry. You can't allocate the component in the calling routine and
>> expect that allocation to stick in spite of the INTENT(OUT). Again,
>> that's because the allocation status of allocatable components is part
>> of the value of the object.
>
>> Reading a variable is much like passing it as an actual argument to an
>> intent(out) dummy. The value is completely determined by whatever is
>> defined from the file or the subroutine. It doesn't keep parts that
>> might have been defined before the read or call.
>
> The claim above is for I/O lists, and would also seem to include WRITE.
>
> Now, it might be that someone wants to reserve these for future
> definition such that the would work. That is, that one could write
> out allocatable data, including the allocation status and size,
> and later read it back in again. (Most likely as UNFORMATTED.)
> If that is the reason, then I probably agree with disallowing
> it for now. Otherwise, it would seem that the obvious way of
> doing it, the way the OP expected, isn't so bad.
>
>> When you directly read an allocated allocatable variable, that's
>> different because what you are really reading is into the contents, much
>> like if it were a pointer and you were reading into the target. (In
>> fact, yes, you can also read into an allocated pointer and that's what
>> happens; you are reading into the target).
>
> -- glen 


0
Reply nospam95 (822) 3/26/2012 2:53:18 AM

Rafik Zurob <nospam@hotmail.com> wrote:

> Regarding formatted I/O with objects containing allocatable components:

> Allocatables are usually represented using descriptors.  A Fortran 
> descriptor typically contains the address of the data, 
> allocation status, rank and bounds information (if applicable), 
> and many other vendor-specific fields.  Technically, all fields 
> are vendor-specific since the standard does not describe or 
> mandate Fortran descriptors, but I'd be surprised if a vendor 
> didn't have the ones above.  The upcoming Technical Specification 
> for further interoperability with C will specify a "C descriptor" 
> format which is basically a standard way of describing parts of 
> the Fortran descriptor.

> So given this, if you have formatted I/O like this:

> type dt
>  real, allocatable :: a(:)
>  real, allocatable :: b(:)
> end type
> type(dt) :: x
> !...
> print *, x

> What should the output be if x%a is unallocated?  

Well, one choice is that it isn't allowed.

> What should it be if both x%a and x%b are unallocated?  
> If the answer is that we should write nothing for unallocated 
> allocatable components, then we'll have problems with READ. 

In the case of UNFORMATTED, one would expect that whatever you
wrote could also be read in with the same result. 

> If the answer is to write something like "(unallocated)", people 
> will be unhappy that their formatted data reports contain text 
> about implementation details.

I say that "(unallocated)" isn't an implementation detail.
The bit patterns that indicated it would be, though.

> On input, if we get 20 comma-separated real values on one line, 
> how do we know how many of these values are part of x%a and how 
> many are part of x%b? 

      print *,a,b

(a and b are assumed shape arrays) You can't tell from what
is printed how many are a and how many are b.

> If x%a and x%b were not allocatable, we can tell by looking 
> at the declared type.  But since they're allocatable, 
> the extent can be anything.  

You also can't tell from assumed shape.

> As Richard explained, if you have "READ *, x", x%a and x%b will 
> be unallocated (and if applicable finalized) before the read 
> just like they are with INTENT(OUT) args.  So all this 
> information has to be discernable from the declared type or 
> the data file we're reading from.

That is a possible situation, but I don't know that it has to
be that way. 

> The standard solves this by offloading these decisions to the user.  
> If a type has allocatable or pointer components, objects of that 
> type can't appear in an I/O list unless the type has a user-defined 
> derived type I/O routine.  That way, users can write output routines 
> that write things in a format that can be read by their input 
> routines, if they wish.

But they can appear without user-defined derived type I/O routines
if they don't have allocatable or pointer components? 

-- glen
0
Reply gah (12253) 3/26/2012 4:47:04 AM

glen herrmannsfeldt <gah@ugcs.caltech.edu> wrote:

> Rafik Zurob <nospam@hotmail.com> wrote:

> > On input, if we get 20 comma-separated real values on one line, 
> > how do we know how many of these values are part of x%a and how 
> > many are part of x%b? 
> 
>       print *,a,b
> 
> (a and b are assumed shape arrays) You can't tell from what
> is printed how many are a and how many are b.
> 
> > If x%a and x%b were not allocatable, we can tell by looking 
> > at the declared type.  But since they're allocatable, 
> > the extent can be anything.  
> 
> You also can't tell from assumed shape.

Note that Rafik said "On input". It does make a difference - a big one.
Among other things, the shape of an assumed-shape array is never
determined by input. It is determined by the associated actual argument.
Thus there is never such a problem for input of an assumed shape array.
For output, it doesn't matter in either case.

I'll not try to go into the various other choices that might have been
made on some of these matters. I'm just not interested in such a
discussion. I do try to explain some of the rationale behind the choices
that were made, but having a rationale is not the same thing as saying
that no other choices would have been possible.

A *LOT* of time was put into debating the various options while
developing the standard. That does not in any way imply that the result
was necessarily perfect or the best of all possible choices. But it does
mean that if you want to do a serious job of looking into all of the
alternatives, you'll also have to spend a lot of time. Feel free, of
course, but I'm not inclined to spend that much of my time discussing it
here. I'll explain rationale when I feel that I can do so, but I won't
try to debate that no other choices would have been possible. Count me
out of further discussion of such possible alternatives in this case.

At times, I regret even trying to explain rationale because that invites
people to start arguing about the other possible choices.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 3/26/2012 5:56:12 AM

In article <jko0ab$flh$1@dont-email.me>,
 Gary Scott <garylscott@sbcglobal.net> wrote:

> >>
> >> It actually appears to be working as designed though...
> >
> > except for:
> >
> > Error 1 error #7822: Variables containing ultimate allocatable array
> > components are forbidden from appearing directly in input/output lists.
> >
> > Why this restriction if I have previously fully allocated all components
> > to match the file content?
> 
> Further testing:  So it appears that I can list each component 
> individually in the I/O statement, just not as a single object.  Does 
> that make sense?  At least it appears that I don't have to massively 
> redesign...

We had a discussion about this very issue a few months ago.

I agree with you.  I think it should be allowed to put the derived 
type variable itself in the i/o list, and it should behave exactly 
the same as specifying the individual components.  But currently it 
is not allowed to do this.

$.02 -Ron Shepard
0
Reply ron-shepard (1197) 3/26/2012 7:36:29 AM

Richard Maine <nospam@see.signature> wrote:

>> Rafik Zurob <nospam@hotmail.com> wrote:
>> > On input, if we get 20 comma-separated real values on one line, 
>> > how do we know how many of these values are part of x%a and how 
>> > many are part of x%b? 
 
>>       print *,a,b

(snip, I wrote)
>> (a and b are assumed shape arrays) You can't tell from what
>> is printed how many are a and how many are b.
 
>> > If x%a and x%b were not allocatable, we can tell by looking 
>> > at the declared type.  But since they're allocatable, 
>> > the extent can be anything.  
 
>> You also can't tell from assumed shape.

> Note that Rafik said "On input". It does make a difference 
> - a big one.
> Among other things, the shape of an assumed-shape array is never
> determined by input. It is determined by the associated 
> actual argument. Thus there is never such a problem for input 
> of an assumed shape array.  For output, it doesn't matter in either case.

OK, I completely missed the point of that question. I had thought,
but only a little, about the combination of allocate on assignment
and READ data input. 

Unless it snuck in when I wasn't looking, there is currently no
Fortran input that allocates to an appropriate size based on the input
data, structures or not.

For array input, one is normally expected to have allocated
the array to an appropriate size (at least big enough) before
a READ statement. I hadn't thought it so bad to allow that for
structure input or output.

> I'll not try to go into the various other choices that might have been
> made on some of these matters. I'm just not interested in such a
> discussion. I do try to explain some of the rationale behind the choices
> that were made, but having a rationale is not the same thing as saying
> that no other choices would have been possible.

> A *LOT* of time was put into debating the various options while
> developing the standard. That does not in any way imply that the result
> was necessarily perfect or the best of all possible choices. But it does
> mean that if you want to do a serious job of looking into all of the
> alternatives, you'll also have to spend a lot of time. Feel free, of
> course, but I'm not inclined to spend that much of my time discussing it
> here. I'll explain rationale when I feel that I can do so, but I won't
> try to debate that no other choices would have been possible. Count me
> out of further discussion of such possible alternatives in this case.

It seems to me that by disallowing it, they leave room for allowing
it in some form in the future.

> At times, I regret even trying to explain rationale because 
> that invites people to start arguing about the other 
> possible choices.

I have been known to discuss (I won't say argue) over the possible
choices when it was already too late. In this case, at least,
there is the possibility for change.

As a slight change of subject, in the Fortran 66 days I remember:

      READ(1) N,(X(I),I=1,N),(Y(I),I=1,N)

The arrays had to be already big enough, as there wasn't an option
for dynamic allocation. One could do:

      READ(1) N
      ALLOCATE (X(N),Y(N))
      BACKSPACE 1
      READ(1) N,(X(I),I=1,N),(Y(I),I=1,N)

With all the usual reasons not to use BACKSPACE. It would be nice
to be able to read such a file and do the allocation.

I suppose one could also consider a structure containing both N
and the arrays. (That is, explicitly containing the size.)

-- glen

0
Reply gah (12253) 3/26/2012 7:39:33 AM

On 3/26/2012 2:39 AM, glen herrmannsfeldt wrote:
> Richard Maine<nospam@see.signature>  wrote:
>
>>> Rafik Zurob<nospam@hotmail.com>  wrote:
>>>> On input, if we get 20 comma-separated real values on one line,
>>>> how do we know how many of these values are part of x%a and how
>>>> many are part of x%b?
>
>>>        print *,a,b
>
> (snip, I wrote)
>>> (a and b are assumed shape arrays) You can't tell from what
>>> is printed how many are a and how many are b.
>
>>>> If x%a and x%b were not allocatable, we can tell by looking
>>>> at the declared type.  But since they're allocatable,
>>>> the extent can be anything.
>
>>> You also can't tell from assumed shape.
>
>> Note that Rafik said "On input". It does make a difference
>> - a big one.
>> Among other things, the shape of an assumed-shape array is never
>> determined by input. It is determined by the associated
>> actual argument. Thus there is never such a problem for input
>> of an assumed shape array.  For output, it doesn't matter in either case.
>
> OK, I completely missed the point of that question. I had thought,
> but only a little, about the combination of allocate on assignment
> and READ data input.

In my case, I store the allocation information myself as part of the 
structure.  I repeat that data along with a record type prefix (an 
ID/handle for the structure).  I read in the record type prefix and 
allocation size, then issue a read for the whole structure, 
pre-allocated to the correct size (including the redundant record type 
and allocation size, i'd rather not backspace).  The redundancy isn't so 
bad, it allows me to do a little cross check.
0
Reply garylscott (1357) 3/26/2012 12:13:55 PM

glen herrmannsfeldt <gah@ugcs.caltech.edu> wrote:

> As a slight change of subject, in the Fortran 66 days I remember:
> 
>       READ(1) N,(X(I),I=1,N),(Y(I),I=1,N)
> 
> The arrays had to be already big enough, as there wasn't an option
> for dynamic allocation. One could do:
> 
>       READ(1) N
>       ALLOCATE (X(N),Y(N))
>       BACKSPACE 1
>       READ(1) N,(X(I),I=1,N),(Y(I),I=1,N)
> 
> With all the usual reasons not to use BACKSPACE. It would be nice
> to be able to read such a file and do the allocation.

Use unformatted stream, at least for new code with the option of newly
specifying the file details.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 3/26/2012 3:23:50 PM

In article <jkp6fk$amr$1@speranza.aioe.org>,
 glen herrmannsfeldt <gah@ugcs.caltech.edu> wrote:

> As a slight change of subject, in the Fortran 66 days I remember:
> 
>       READ(1) N,(X(I),I=1,N),(Y(I),I=1,N)

Just in case there is confusion because of the reference to f66, the 
above is still legal and standard conforming now.

> The arrays had to be already big enough, as there wasn't an option
> for dynamic allocation. One could do:
> 
>       READ(1) N
>       ALLOCATE (X(N),Y(N))
>       BACKSPACE 1
>       READ(1) N,(X(I),I=1,N),(Y(I),I=1,N)
> 
> With all the usual reasons not to use BACKSPACE. It would be nice
> to be able to read such a file and do the allocation.

Or, the N could be written to a separate record, and then the above 
works naturally with no backspace being required.  Also, there is 
now nonadvancing i/o that can be used for these situations, for 
example, when the programmer does not have control of the file 
format.

> I suppose one could also consider a structure containing both N
> and the arrays. (That is, explicitly containing the size.)

To me, this whole issue of thinking of i/o as being equivalent to 
allocate on assignment or as an INTENT(OUT) dummy argument is a red 
herring.  If you don't think of i/o that way, then doing i/o on 
derived types is perfectly natural.  I remember the first time I ran 
into this issue, I thought it must be a compiler error.  It truly 
was surprising to me that this was not included, specified, and 
document in the standard.

Also, if it had been defined to work this way in the beginning, then 
that would not have precluded some later extension to allow dynamic 
assignment on read (or whatever the reason the committee is holding 
back).

$.02 -Ron Shepard
0
Reply ron-shepard (1197) 3/26/2012 3:42:21 PM

Ron Shepard <ron-shepard@NOSPAM.comcast.net> wrote:

> In article <jkp6fk$amr$1@speranza.aioe.org>,
>  glen herrmannsfeldt <gah@ugcs.caltech.edu> wrote:

> >       READ(1) N
> >       ALLOCATE (X(N),Y(N))
> >       BACKSPACE 1
> >       READ(1) N,(X(I),I=1,N),(Y(I),I=1,N)
> > 
> > With all the usual reasons not to use BACKSPACE. It would be nice
> > to be able to read such a file and do the allocation.
> 
> Or, the N could be written to a separate record, and then the above 
> works naturally with no backspace being required.  Also, there is 
> now nonadvancing i/o that can be used for these situations, for 
> example, when the programmer does not have control of the file 
> format.

Non-advancing doesn't apply to unformatted, though. That's why I
mentioned unformatted stream instead, though that won't work so well for
existing sequential unformatted files (you can probably do it, but it
isn't guaranteed and requires making assumptions about the structure of
unformatted sequential).

> To me, this whole issue of thinking of i/o as being equivalent to 
> allocate on assignment or as an INTENT(OUT) dummy argument is a red 
> herring.  If you don't think of i/o that way, then doing i/o on 
> derived types is perfectly natural.

Well, even without reference to assignment or intent(out), one
implementation aspect sure jumps out at me. I'm used to unformatted I/O
being simply and literally copying the bits of each item to or from the
file. If an item has allocatable components, implementation has to be
fundamentally different. Even if one requires that the components be
pre-allocated to the right size, the data from the file still has to be
split up and put in different memory locations. If you want allocation
based on something in the file, it actually has to read information
about the shape (which has to be in the file), do the allocation, and
then separately read data into the allocated space.

That's very much like what you'd do as a user taking advantage of
UDDTIO. I'll skip over the facts that UDDTIO is both one of my least
favorite f2003 features and pretty consistently one of the last to get
implemented in compilers, but it does pretty directly provide a hook for
this kind of functionality, even allowing substantial user choice in how
to work the details. I'll admit it is awfully verbose (somewhat like my
posts).

Of course, pointers are worse because it would take major rework of lots
of things to be able to indicate a pointer target in a way that would
make sense in any context other than subsequently reading back into the
same instance of the same program. That one has little hope in Fortran.

An apparently unrelated detail relates to the standard's support of
"just dump the bits to the file" implementations. (Yes, I'm sounding
like Glen in paying so much attention to implementation details as
rationale for feature choices.) The standard has what might otherwise
seem like a strange exception to the principle that writing a structure
to a file is equivalent to writing its components. That equivalence is
not so for all cases of unformatted I/O. The reason (at least what I
infer to be the reason) is that a structure might be stored in memory
dfferently from the way that a separate list of its components would
imply. In particular, the structure could have padding or reordering of
the components for the sake of alignment or other reasons. By specifying
that the structure is not equivalent to a list of its components, the
standard allows the compiler to still just dump the bits of the
structure to the file; those same bits will work fine if you read them
back in to a structure of the same type, with no fiddling required.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 3/26/2012 4:57:54 PM

Ron Shepard <ron-shepard@nospam.comcast.net> wrote:
> In article <jkp6fk$amr$1@speranza.aioe.org>,

(snip, I wrote)
>> As a slight change of subject, in the Fortran 66 days I remember:
 
>>       READ(1) N,(X(I),I=1,N),(Y(I),I=1,N)

> Just in case there is confusion because of the reference to f66, the 
> above is still legal and standard conforming now.

Yes, I should have said that. In the f66 days, though, X and Y
couldn't have been dynamically allocated so there was no reason
to consider that case. 

(snip on BACKSPACE, and dynamic allocation)

> Or, the N could be written to a separate record, and then the above 
> works naturally with no backspace being required.  Also, there is 
> now nonadvancing i/o that can be used for these situations, for 
> example, when the programmer does not have control of the file 
> format.

There were enough WRITE statements writing the file (different
parts of the program) that I liked that it could be done in
one statement. 

>> I suppose one could also consider a structure containing both N
>> and the arrays. (That is, explicitly containing the size.)

> To me, this whole issue of thinking of i/o as being equivalent to 
> allocate on assignment or as an INTENT(OUT) dummy argument is a red 
> herring.  

Well, if you ask that, I would have made allocate on assignment
somehow different from ordinary assignment. Either an attribute
on the variable, or a special assignment statement. It does have
at least some overhead that you might want to avoid.

> If you don't think of i/o that way, then doing i/o on derived 
> types is perfectly natural.  I remember the first time I ran 
> into this issue, I thought it must be a compiler error.  It truly 
> was surprising to me that this was not included, specified, and 
> document in the standard.

Continuing, if later allocate on READ was added, it could be an
option specified on the READ statement, such that ordinary structure
read would work, with preallocated arrays, without that option.

As I said before, the reason I can see for not doing it yet is to wait
until allocate on READ is added.

> Also, if it had been defined to work this way in the beginning, then 
> that would not have precluded some later extension to allow dynamic 
> assignment on read (or whatever the reason the committee is holding 
> back).

My biggest complaint about Fortran is that there are too many
special case rules. Many have been removed over the years, but
then new ones are added. Some are needed to keep compatible with
older programs, but not all of them.

Special case rules require remembering those cases, or looking them
up, making it harder to write programs. Looking them up requries
that you remember that there is a case that needs looking up.

-- glen
0
Reply gah (12253) 3/26/2012 8:49:29 PM

22 Replies
104 Views

(page loaded in 0.188 seconds)

Similiar Articles:






7/23/2012 10:49:35 PM


Reply: