Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Transfer and variables that don't use all their storage space.

16 views
Skip to first unread message

Brooks Moses

unread,
Apr 8, 2007, 9:02:08 PM4/8/07
to
Hello, all!

I'm working on implementing compile-time handling of the transfer
intrinsic for GFortran, and have a couple of edge-case questions about
the standard that I'm hoping someone here can comment on.

The Fortran 2003 standard states that TRANSFER(TRANSFER(E,D),E) should
result in E, if D and E are scalar variables and the physical
representation of D is as long as or longer than that of E. (Section
13.7.121, lines 30-32.)

Now, consider a processor which supports 4-byte LOGICAL and INTEGER
variables, and suppose that D is a LOGICAL and E is an INTEGER.
Further, suppose that the canonical representations of 4-byte logicals
in this processor are to flip the 1-bit to either 1 or 0, and leave the
rest zero.

A naive reading of the double-transfer requirement would claim that, if
E is some number other than 1 or 0, then the processor is required to
feed that into D's storage space and leave it there, so that it can then
be converted back into the same number by the outer transfer statement.
In particular, according to this reading, the inner transfer statement
cannot "normalize" the bit representation into one of the canonical
LOGICAL forms, because then the outer transfer statement would return
either 1 or 0, neither of which is equal to E.

I would contend that this reading is incorrect -- that, in particular,
if E has a bit representation that is not one of the canonical bit
representations for a logical variable, then the inner transfer
statement is illegal according to the comments in the beginning of
section 13.7 which state that a program is not allowed to invoke an
intrinsic with arguments that produce out-of-range results. And further
that the double-transfer identity requirement obviously is only meant to
apply when both transfer calls, taken independently, are legal.

Is that a reasonable contention?

Further, a strictly literal reading of the beginning of section 13.7
would suggest that when transferring a value to a real number, NaN
should be returned if the bit representation is not a legal real number.
In particular, this might apply for 80-bit real numbers that are
stored in 12 bytes, if the extraneous 12 bytes are non-zero (or whatever
their "usual" state is). I'm hoping that this is reading things
excessively finely, but I suppose I should ask rather than assuming such.

- Brooks


--
The "bmoses-nospam" address is valid; no unmunging needed.

Richard Maine

unread,
Apr 8, 2007, 9:39:43 PM4/8/07
to
Brooks Moses <bmoses...@cits1.stanford.edu> wrote:

> I'm working on implementing compile-time handling of the transfer
> intrinsic for GFortran, and have a couple of edge-case questions about
> the standard that I'm hoping someone here can comment on.

Edge cases of TRANSFER are a mess. I'm convinced the standard is
inconsistent about some of them. Anyway...

> The Fortran 2003 standard states that TRANSFER(TRANSFER(E,D),E) should
> result in E, if D and E are scalar variables and the physical
> representation of D is as long as or longer than that of E. (Section
> 13.7.121, lines 30-32.)

That's one part I'm sure is inconsistent. That can't realistically be
expected to work in all cases. I think that whoever wrote those words
just didn't think of the edge cases at all. Consider a scalar of a type
that has allocatable components (perhaps multiple of them, at multiple
depths). I really don't think that the standard envisions going through
and doing all the allocations that would be needed to make that work;
and I sure don't know what the intermediate bits would be.

That's without even thinking of issues like hardware locations that just
don't allow some bit patterns - fortunately that's not a typical
situation for today's machines.

> Now, consider a processor which supports 4-byte LOGICAL and INTEGER
> variables, and suppose that D is a LOGICAL and E is an INTEGER.
> Further, suppose that the canonical representations of 4-byte logicals
> in this processor are to flip the 1-bit to either 1 or 0, and leave the
> rest zero.
>
> A naive reading of the double-transfer requirement would claim that, if
> E is some number other than 1 or 0, then the processor is required to
> feed that into D's storage space and leave it there, so that it can then
> be converted back into the same number by the outer transfer statement.
> In particular, according to this reading, the inner transfer statement
> cannot "normalize" the bit representation into one of the canonical
> LOGICAL forms, because then the outer transfer statement would return
> either 1 or 0, neither of which is equal to E.

I think I agree with that. I'm not sure what is naive about it. It is
pretty explicit that all transfer does is copy bits - not convert them.
The bit that you quoted about transfer(transfer(e,d),e) is more of an
elaboration of what you'd expect (in simple cases) to result from
transfering the bits. I think it belongs as a note instead of as
normative text. (And it probably should be corrected with
qualifications, even as a note.)



> I would contend that this reading is incorrect -- that, in particular,
> if E has a bit representation that is not one of the canonical bit
> representations for a logical variable, then the inner transfer
> statement is illegal according to the comments in the beginning of
> section 13.7 which state that a program is not allowed to invoke an
> intrinsic with arguments that produce out-of-range results. And further
> that the double-transfer identity requirement obviously is only meant to
> apply when both transfer calls, taken independently, are legal.

I agree, except with your comment that the para before is incorrect.
These two paras don't seem inconsistent to me. I think *BOTH* of them
are right. The first para describes what the standard requires to happen
(that the bits just get copied without change). The second para
correctly (in my view) notes that this requires disallowed behavior in
some cases. I agree with the conclusion that the code is illegal on
machines where the resulting bit pattern is an invalid one.

> Further, a strictly literal reading of the beginning of section 13.7
> would suggest that when transferring a value to a real number, NaN
> should be returned if the bit representation is not a legal real number.

I don't see that. As mentioned above, the essential definition of
TRANSFER is that is just copies the bits. I don't think it ever does any
kind of manipulation of them, such as normalizing, generating NaNs or
anything of the sort. You just get the bits as is. If those bits aren't
valid for any reason, then the code is illegal. Note that assignment can
do things like normalize, so the result of

somevariable = transfer(something,somevariable)

might end up with somevariable being normalized, even though the
transfer intrinsic didn't do it.

--
Richard Maine | Good judgement comes from experience;
email: last name at domain . net | experience comes from bad judgement.
domain: summertriangle | -- Mark Twain

James Giles

unread,
Apr 8, 2007, 10:45:38 PM4/8/07
to
Richard Maine wrote:

> Brooks Moses <bmoses...@cits1.stanford.edu> wrote:
...
>> The Fortran 2003 standard states that TRANSFER(TRANSFER(E,D),E)
>> should result in E, if D and E are scalar variables and the physical
>> representation of D is as long as or longer than that of E. (Section
>> 13.7.121, lines 30-32.)
>
> That's one part I'm sure is inconsistent. That can't realistically be
> expected to work in all cases. I think that whoever wrote those words
> just didn't think of the edge cases at all. Consider a scalar of a
> type that has allocatable components (perhaps multiple of them, at
> multiple depths). I really don't think that the standard envisions
> going through and doing all the allocations that would be needed to
> make that work; and I sure don't know what the intermediate bits
> would be.

The internal representation of ALLOCATABLE components
of a derived type would almost certainly be very similar to the
internal representation of a POINTER component. It would
probably consist of an address field, some fields to describe
the bounds of the allocated object in each of its dimensions,
and some tags specifying status (at least one: whether the object
is allocated or not). As such, that internal representation
probably takes up the same amount of room whether the
components are allocated or not. What TRANSFER would
operate on would be the implementation dependent bits of
such a hidden descriptor. People have used such tricks to
reverse engineer and then manipulate the internal representation
of POINTERs before now.

--
J. Giles

"I conclude that there are two ways of constructing a software
design: One way is to make it so simple that there are obviously
no deficiencies and the other way is to make it so complicated
that there are no obvious deficiencies." -- C. A. R. Hoare


Brooks Moses

unread,
Apr 8, 2007, 10:46:19 PM4/8/07
to
Richard Maine wrote:
> Brooks Moses <bmoses...@cits1.stanford.edu> wrote:
>> A naive reading of the double-transfer requirement would claim that, if
>> E is some number other than 1 or 0, then the processor is required to
>> feed that into D's storage space and leave it there, so that it can then
>> be converted back into the same number by the outer transfer statement.
>> In particular, according to this reading, the inner transfer statement
>> cannot "normalize" the bit representation into one of the canonical
>> LOGICAL forms, because then the outer transfer statement would return
>> either 1 or 0, neither of which is equal to E.
>
> I think I agree with that. I'm not sure what is naive about it. It is
> pretty explicit that all transfer does is copy bits - not convert them.
> The bit that you quoted about transfer(transfer(e,d),e) is more of an
> elaboration of what you'd expect (in simple cases) to result from
> transfering the bits. I think it belongs as a note instead of as
> normative text. (And it probably should be corrected with
> qualifications, even as a note.)

I mean "naive" in the sense of looking just at that paragraph, without
considering context or outside knowledge. I don't mean that I think
it's necessarily wrong.

>> I would contend that this reading is incorrect -- that, in particular,
>> if E has a bit representation that is not one of the canonical bit
>> representations for a logical variable, then the inner transfer
>> statement is illegal according to the comments in the beginning of
>> section 13.7 which state that a program is not allowed to invoke an
>> intrinsic with arguments that produce out-of-range results. And further
>> that the double-transfer identity requirement obviously is only meant to
>> apply when both transfer calls, taken independently, are legal.
>
> I agree, except with your comment that the para before is incorrect.
> These two paras don't seem inconsistent to me. I think *BOTH* of them
> are right. The first para describes what the standard requires to happen
> (that the bits just get copied without change). The second para
> correctly (in my view) notes that this requires disallowed behavior in
> some cases. I agree with the conclusion that the code is illegal on
> machines where the resulting bit pattern is an invalid one.

I think I'm confused as to what it means, in practical terms, when "the
standard ... requires disallowed behavior". I'm not sure how to write a
compiler that disappears in a puff of logic in such cases! :)

Perhaps it would be useful for me to elaborate a bit more on why I'm
asking this question. GFortran currently, in its handling of
initialization expressions, treats all logical variables as simple
booleans, stored for convenience in whatever the host considers to be a
default integer (which is usually 4 bytes). However, it supports 8-byte
logical variables. Thus, consider the following program-piece:

logical(kind=8) :: L
integer :: A( -transfer(transfer(-5_8, L), -5_8) )

(Note that, in GFortran, KIND=8 logicals and integers are 8-byte.)

In order to do the initialization-expression handling to reliably
produce a 5-element array out of this, the constant-folder for the inner
transfer evaluation needs to store all eight bytes of the result.

Doing that would either require that the entire initialization-
expression evaluation mechanism store all logical variables in a way
that records all eight bytes of "target storage" even though they are
almost never meaningful, or else the parser has to recognize this
particular idiom and handle it specially. Neither of these is a very
appealing option, and that's just one of the simpler cases.

However, if this is illegal code, then I would think that it would be
entirely standard-conforming for the compiler to do just about anything
with this code, and thus such measures are unnecessary.


If I understand your above comments correctly, you've agreed that this
is illegal code, but you also explicitly agreed with the second half of
my first paragraph (the bit starting with "In particular," which says
that transfer(transfer(-5_8, L), -5_8) must return -5, not 1. It seems
completely counterintuitive to me that the compiler is required to
produce a specific result for illegal code. However, that's what I'm
understanding you to be saying.

Would it be allowable, at least, for a compiler to throw an error and
refuse to compile "transfer(transfer(-5_8, L), -5_8)" at all?

Richard Maine

unread,
Apr 9, 2007, 12:12:04 AM4/9/07
to
James Giles <james...@worldnet.att.net> wrote:

> Richard Maine wrote:
> > Brooks Moses <bmoses...@cits1.stanford.edu> wrote:
> ...
> >> The Fortran 2003 standard states that TRANSFER(TRANSFER(E,D),E)
> >> should result in E, if D and E are scalar variables and the physical
> >> representation of D is as long as or longer than that of E. (Section
> >> 13.7.121, lines 30-32.)
> >
> > That's one part I'm sure is inconsistent. That can't realistically be
> > expected to work in all cases. I think that whoever wrote those words
> > just didn't think of the edge cases at all. Consider a scalar of a
> > type that has allocatable components (perhaps multiple of them, at
> > multiple depths). I really don't think that the standard envisions
> > going through and doing all the allocations that would be needed to
> > make that work; and I sure don't know what the intermediate bits
> > would be.
>
> The internal representation of ALLOCATABLE components
> of a derived type would almost certainly be very similar to the

> internal representation of a POINTER component....


> What TRANSFER would
> operate on would be the implementation dependent bits of
> such a hidden descriptor.

Yes, that's what I would expect. *HOWEVER*, if you transfer the bits of
such a descriptor that is allocated, you are likely to end up with two
different allocated allocatables trying to use the same storage. That is
certainly not envisioned and is likely to cause havoc. A straightforward
reading of the words that Brooks cited above seems to suggest that it
ought to work, since the resulting variable is claimed to have the same
value as the original. That's the kind of situation I'm envisioning, and
I think the cited words of the standard completely fall apart for cases
like that.

Yes, I can imagine what I'd expect to happen in practice, based on
transfer just copying the bits, and I can imagine people trying to take
advantage of that for system-dependent stuff. No debate there. I'm
talking purely about standard-conforming code, and code that the
standard claims ought to be portable as well by the above citation.

Richard Maine

unread,
Apr 9, 2007, 12:28:36 AM4/9/07
to
Brooks Moses <bmoses...@cits1.stanford.edu> wrote:

> Richard Maine wrote:

> I think I'm confused as to what it means, in practical terms, when "the
> standard ... requires disallowed behavior".

My phrasing of that isn't the world's best (or even second best :-)),
but I was basically agreeing with what seemed to be your logic. If the
standard requires behavior that the standard also disallows, I think one
can deduce that code that does that is non-conforming (by one of those
basic section 1.4 arguments). Thus the compiler can do anything.

> Doing that would either require that the entire initialization-
> expression evaluation mechanism store all logical variables in a way
> that records all eight bytes of "target storage" even though they are
> almost never meaningful,

Ok. I'm the naive one here, but I think that is the behavior anticipated
by the standard. If variables of a type (the 8-byte logical one or any
other) can be used as repositories of arbitrary bits by transfer, then
it seems to me that you need to store all those bits. Perhaps in special
cases, you can deduce that you can optimize storage of some of them
away, but that seems like an optimization to me.

> If I understand your above comments correctly, you've agreed that this
> is illegal code, but you also explicitly agreed with the second half of
> my first paragraph (the bit starting with "In particular," which says
> that transfer(transfer(-5_8, L), -5_8) must return -5, not 1. It seems
> completely counterintuitive to me that the compiler is required to
> produce a specific result for illegal code. However, that's what I'm
> understanding you to be saying.

No. I'm using a back door argument to explain why the code is illegal.
More or less a proof by contradiction, which is perhaps why it seems
contradictory. :-) I arise at a contradiction if I assume the code is
standard conforming. The contradiction is that the standard requires a
result that the standard also prohibits. Thus, I conclude that the
assumption of standard conformance is false.

> Would it be allowable, at least, for a compiler to throw an error and
> refuse to compile "transfer(transfer(-5_8, L), -5_8)" at all?

I think you could argue that. But then you might get users who
considered it a poor quality of implementation; that one is harder. I
have trouble imagining why anyone would ever want to do such a strange
thing, but James Buskirk can probably come up with something useful. :-)

I think the more "obvious" thing to do is to use all 8 bytes. But I
don't know what the costs of that are and what the tradoffs might be of
those costs versus the (rare?) usage of an idiom like that.

James Giles

unread,
Apr 9, 2007, 12:42:18 AM4/9/07
to
Richard Maine wrote:
> James Giles <james...@worldnet.att.net> wrote:
...

>> The internal representation of ALLOCATABLE components
>> of a derived type would almost certainly be very similar to the
>> internal representation of a POINTER component....
>> What TRANSFER would
>> operate on would be the implementation dependent bits of
>> such a hidden descriptor.
>
> Yes, that's what I would expect. *HOWEVER*, if you transfer the bits
> of such a descriptor that is allocated, you are likely to end up with
> two different allocated allocatables trying to use the same storage.
> That is certainly not envisioned and is likely to cause havoc. A
> straightforward reading of the words that Brooks cited above seems to
> suggest that it ought to work, since the resulting variable is
> claimed to have the same value as the original. That's the kind of
> situation I'm envisioning, and I think the cited words of the
> standard completely fall apart for cases like that.
>
> Yes, I can imagine what I'd expect to happen in practice, based on
> transfer just copying the bits, and I can imagine people trying to
> take advantage of that for system-dependent stuff. No debate there.
> I'm talking purely about standard-conforming code, and code that the
> standard claims ought to be portable as well by the above citation.

There are a lot of things that can cause havoc. I think the committee
probably envisioned that abuse of TRANSFER would cause havoc.
Everything about TRANSFER is implementation dependent. So, its
not even possible to discuss the havoc (except speculatively) without
stating what implementation you're talking about. The semantics of
TRANSFER are defined in terms of *representations* and not
*values*. The fact that the resulting *values* are meaningless (the
LOGICAL result transferred from INTEGER, for example) or even
dangerous (multiple ALLOCATABLE components associated with
the same storage) is the programmer's responsibility.

Still, I don't see the ALLOCATABLE components problem as all
that bad. The result of TRANSFER must be assigned or it's lost.
(OK, it could also be an actual argument to a procedure, and maybe
there are other uses I can't think of on an Easter night. But let's
consider
the obvious first.) So, suppose you do:

var = transfer(transfer(E, D), E)

Where E and VAR are both some derived type and D is some type
big enough to hold all the bits of the derived type. In this case, the
ALLOCATABLE components of VAR do *not* end up associated
with the same storage as the components of E. This is because of
the semantics of assignment. It has nothing to do with TRANSFER
at all. It's the same result as if you had written var = E. It may be
that the other cases, such as passing the result of TRANSFER as an
actual argument to a procedure, turn out to be equally benign. You
would have to go through each possibility carefully. If they aren't
all benign, well that's one of the kinds of havoc.

Richard Maine

unread,
Apr 9, 2007, 1:54:18 AM4/9/07
to
James Giles <james...@worldnet.att.net> wrote:

> Still, I don't see the ALLOCATABLE components problem as all
> that bad. The result of TRANSFER must be assigned or it's lost.
> (OK, it could also be an actual argument to a procedure, and maybe
> there are other uses I can't think of on an Easter night. But let's
> consider the obvious first.)

Yes, I did. And I agree that can fix it. I didn't post those details,
but I came to the same conclusion as you did about the likely result of
using assignment. But I claim that the actual argument case can cause
crashes and other "havoc" in code that the standard appears to claim is
standard-conforming and *NOT* processor-dependent. In particular, the
bit about the result having the same value as E is stated as an absolute
- not a processor dependence.

And no, I don't think the authors of the standard consciously thought
about such things. Rather the opposite, I think such matters were
completely overlooked in writing the simplistic words that Brooks cited.

James Giles

unread,
Apr 9, 2007, 2:41:32 AM4/9/07
to
Richard Maine wrote:
...

> And no, I don't think the authors of the standard consciously thought
> about such things. Rather the opposite, I think such matters were
> completely overlooked in writing the simplistic words that Brooks
> cited.

The point I was making was that I believe the committee deliberately
overlooked such issues. The purpose of TRANSFER was to provide
a means of doing things that the language otherwise didn't permit.
The fact that such activities could be abused was the programmer's
responsibility.

glen herrmannsfeldt

unread,
Apr 9, 2007, 8:48:58 AM4/9/07
to
Brooks Moses wrote:
(snip)

> I would contend that this reading is incorrect -- that, in particular,
> if E has a bit representation that is not one of the canonical bit
> representations for a logical variable, then the inner transfer
> statement is illegal according to the comments in the beginning of
> section 13.7 which state that a program is not allowed to invoke an
> intrinsic with arguments that produce out-of-range results. And further
> that the double-transfer identity requirement obviously is only meant to
> apply when both transfer calls, taken independently, are legal.

In Fortran 66, before CHARACTER variables, the standard allowed
storing of character data, read and written with A format, in
other types of variables. It was, then, fairly easy to get bit
representations that would not normally be allowed for that data
type, especially for LOGICAL. In that case, one would have to
be careful how the data was used, but it was at least expected
that assignment to another variable would work.

> Is that a reasonable contention?

In general, I don't believe so. There are some conditions which I
might wonder about, one is floating point. On machines with
unnormalized values, assignment might do normalization.

> Further, a strictly literal reading of the beginning of section 13.7
> would suggest that when transferring a value to a real number, NaN
> should be returned if the bit representation is not a legal real number.
> In particular, this might apply for 80-bit real numbers that are stored
> in 12 bytes, if the extraneous 12 bytes are non-zero (or whatever their
> "usual" state is). I'm hoping that this is reading things excessively
> finely, but I suppose I should ask rather than assuming such.

Assignment of 12 byte reals could be done by byte copying, instead of
loading into a floating point register and storing from there.

-- glen

Michael Metcalf

unread,
Apr 9, 2007, 7:57:23 AM4/9/07
to

"James Giles" <james...@worldnet.att.net> wrote in message
news:welSh.27857$VU4....@bgtnsc05-news.ops.worldnet.att.net...

>
> The point I was making was that I believe the committee deliberately
> overlooked such issues. The purpose of TRANSFER was to provide
> a means of doing things that the language otherwise didn't permit.
> The fact that such activities could be abused was the programmer's
> responsibility.
>
Well, it's 21(!) years ago, but my notes on the Halifax meeting in 1986
include:

"Transfer function

My attempts at the previous meeting to restore some form of storage mapping
had failed, but I had been asked to come back with proposals for a transfer
function to allow one area of storage to be viewed as containing more than
one data type. I had prepared two proposals for the meeting but, following
suggestions by John Reid, I rewrote the proposals in the form of a single
function able to return either scalar or array-valued results, depending on
a MOLD argument. This was accepted 20-4. This function would allow us [the
HEP community] to replace code of the form

COMMON//Q(10000)
INTEGER IQ(1)
EQUIVALENCE (IQ,Q)
:
PX = Q(IQ(L) + 3)

by

COMMON//Q(10000)
:
PX = Q(TRANSFER(Q(L), 0) + 3) ! second argument moulds Q(L) to an
! integer scalar"

The only remaining argument was whether the language should *deliberately*
contain an 'unsafe' feature. The functionality was always regarded as taking
two different views of the same storage.

HTH,

Mike Metcalf


Richard Maine

unread,
Apr 9, 2007, 11:23:38 AM4/9/07
to
James Giles <james...@worldnet.att.net> wrote:

> Richard Maine wrote:
> ...
> > And no, I don't think the authors of the standard consciously thought
> > about such things. Rather the opposite, I think such matters were
> > completely overlooked in writing the simplistic words that Brooks
> > cited.
>
> The point I was making was that I believe the committee deliberately
> overlooked such issues. The purpose of TRANSFER was to provide
> a means of doing things that the language otherwise didn't permit.
> The fact that such activities could be abused was the programmer's
> responsibility.

We appear to be miscommunicating. I agree that transfer is to provide a
means of doing such things. That is not my point. Have you reread the
sentence from the standard that Brooks cited? That sentence specifically
says what some cases give as a result, and it says it in a fashion that
is not system dependent. You don't need that sentence to provide
system-dependent capability; quite the opposite - that sentence
disallows system dependence.

It is that sentence and only that sentence that I am arguing about. I
don't see that your argument has anything to do with that sentence. If
you do, then I guess we are just going to have to disagree. I continue
to think that the sentence reflects an inadvertant oversight.

Richard Maine

unread,
Apr 9, 2007, 11:30:26 AM4/9/07
to
glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:

> In Fortran 66, before CHARACTER variables, the standard allowed
> storing of character data, read and written with A format, in
> other types of variables.

A more "interesting" case was "statement label values" (aka addresses)
stored in integer variables with the ASSIGN statement. That's
"interesting" because on some architectures they don't "fit". There have
actually been implementations (several of them) where an integer
variable used for such things had two separate addresses of different
sizes, depending on whether it stored an integer value or a statement
label value.

Brooks:


> > Is that a reasonable contention?
>
> In general, I don't believe so. There are some conditions which I
> might wonder about, one is floating point. On machines with
> unnormalized values, assignment might do normalization.

Assignment is an different question. The question asked about the
transfer intrinsic itself - not about assignment of its result. Those
are *NOT* the same thing. A function result can be used without
assigning it.

> Assignment of 12 byte reals could be done by byte copying, instead of
> loading into a floating point register and storing from there.

Again, the question is not about assignment. The distinction matters.

James Giles

unread,
Apr 9, 2007, 12:10:40 PM4/9/07
to
Richard Maine wrote:
> We appear to be miscommunicating. I agree that transfer is to provide
> a means of doing such things. That is not my point. Have you reread
> the sentence from the standard that Brooks cited? That sentence
> specifically says what some cases give as a result, and it says it in
> a fashion that is not system dependent. You don't need that sentence
> to provide system-dependent capability; quite the opposite - that
> sentence disallows system dependence.

Well, I've thought it over again and I can't see any difference
between passing transfer(transfer(E,D),E)) as an actual argument
and just passing E as the actual argument except the following:
the result of TRANSFER may not be argument associated
with a dummy argument that has OUT among its INTENTs.
I don't see how that difference could cause "havoc". So, at
least as far as the issue of ALLOCATABLE components,
I still see no problems.

I suppose you can continue to speculate that there *might* be
problems with requiring the double transfer above to be the
identity operation. But it will remain just that: speculation.
Without a concrete example of such a problem it seems to
me that there are better things to do with one's time. For
all we know, someone in the F90 committee carefully thought
through all possible cases and found no "havoc" arising from
any of them. That's speculation too (unless someone remembers
it). It seems as likely as that there *is* a problem with the
requirement that no one can identify after all these years.

Richard Maine

unread,
Apr 9, 2007, 12:57:06 PM4/9/07
to
James Giles <james...@worldnet.att.net> wrote:

> Richard Maine wrote:
> > That sentence
> > specifically says what some cases give as a result, and it says it in
> > a fashion that is not system dependent.

> Well, I've thought it over again and I can't see any difference


> between passing transfer(transfer(E,D),E)) as an actual argument
> and just passing E as the actual argument except the following:
> the result of TRANSFER may not be argument associated
> with a dummy argument that has OUT among its INTENTs.
> I don't see how that difference could cause "havoc". So, at
> least as far as the issue of ALLOCATABLE components,
> I still see no problems.

I need to use a temp variable to get the effect. First, I claim that
introducing an intermediate variable cannot change the standard's claim
that transfer((transfer(e,d),e) must return E. If that made a
difference, then that would mean that the result of transfer was somehow
not captured in its value. In particular, if we change it to

d = transfer(e,d)
now use transfer(d,e)

This is for a case where D is of a "benign" type where the assignment
operator doesn't do anything "odd".

So do

d = transfer(e,d)
call sub(transfer(d,ee),e)

where ee is another vairiable of the same type as e. I probably don't
even need it, but I use it to remove any question that the first
argument might have any reference to e. Now in the subroutine

subroutine sub(ee,e)
...

I can imagine a fair chance that the allocatable components of e and ee
have managed to get "associated". Well, not as defined by the standard
because it doesn't have any concept like that for allocatables. But if
you change the value of the allocatable component of e, that's likely to
also change the value of the component of ee. Deallocating e could have
other more "interesting" results such as the component of e pointing to
storage that is used for some random other thing. I don't see that this
code violates any of the rules of the standard. In particular, the
actual arguments aren't associated in any way acknowledged by the
standard, so the prohibitions against changing the values of the dummies
don't apply. You can't directly change the value of the first dummy
because its actual is an expression, but you can change the value of the
second.

That's just a pretty much off-the-top-of-my head example. It is slightly
indirect because I did keep running into bars (some of the same ones you
mentioned), but I methodically worked around each one.

Once you have a single "hole" like this, you can open up many others.

> For
> all we know, someone in the F90 committee carefully thought
> through all possible cases and found no "havoc" arising from
> any of them.

You have *GOT* to be kidding. :-) Yes, I saw that you labelled it as
speculation. But I don't even think it is very plausible speculation.
I've seentoo much of the committee close up; I don't think they would
have thought through all the cases of that one, particularly as...

> That's speculation too (unless someone remembers
> it). It seems as likely as that there *is* a problem with the
> requirement that no one can identify after all these years.


"All these years" isn't very many for allocatable components, which are
where I can most readily see a related problem. Wouldn't surprise me if
there are others, but that's one I think I can see concretely. There's
no way that whoever wrote the transfer description for f90 could have
carefully considered how it worked with allocatable components, the
details of which weren't done til a decade later. I was there during all
of the work on allocatable components, and I don't recall any such topic
relating to transfer ever having been broached. I do recall that
allocatable components had lots and lots of subtleties that took a long
time to work out, both in the standard and in implementations. They seem
like such a simple and "obvious" thing that many people don't see why
they took so long. There was a time when I didn't appreciate the issues.
My first attempts at f90 code, before I had a compiler to check me, used
allocatable components because I just assumed that, of course, you could
do that since you had allocatables and you had components.

Richard Maine

unread,
Apr 9, 2007, 2:04:49 PM4/9/07
to
Richard Maine <nos...@see.signature> wrote:

> James Giles <james...@worldnet.att.net> wrote:

> > So, at
> > least as far as the issue of ALLOCATABLE components,

> > I still see no problems [with transfer].
>
> [I gave an example of a problem I see with allocatable components]

But I neglected to mention a related actual problem I once had. It
wasn't with allocatable components, being long before they were valid.
It was instead with pointer components. Pointer components aren't
necessarily as "bad" for this. One could imagine all as working just
fine. It is normal for multiple pointers to have the same target and
there are rules for how they interact. But still, I have had related
problems.

In particular, I have had transfer of pointer components cause problems
with garbage collection. I don't do that kind of thing any more. My
experiences with it were too painful. It is also some of the stuff that
I can see that the f2003 object oriented features would help make
cleaner. For the interim, I used other methods, that don't seem as
elegant or flexible, but did the job for my application. Anyway...

I had a derived type with a pointer component. Actualy, multiple
different derived types, each with different pointer components. It is
determined at run-time which type is being used. In order to fake what I
know know of as polymorphism (though I hadn't heard of the term then), I
used transfer to store the bits in storage of a "neutral" type (I used
an array of integers). The higher level code didn't then need to know
the details of the different lower-level types. The bits were later
transferred back into the appropriate type when it was needed to use
them. But... sometimes the compiler's garbage collection would run while
the bits were stored in the "neutral" type. The pointer targets looked
like allocated memory that had no current pointers to it. So it got
garbage collected. When I later transfered the bits back to the right
type, the targets were gone.

In some senses, I'm not sure this is as good an example of problems as
the allocatable one. But this is one that I actually got bit (um, pun
not intended, or even noticed until I reread this) by in the early 90's.
It is what made me start thinking about the possibility of cases where
just naively copying the bits might not have the effect of copying all
the information correctly. One example that occurred to me (but I don't
think I've seen) would be relative addressing of pointers. If you have
relative addressing, then copying the same bits to another location
doesn't preserve their meaning.

James Giles

unread,
Apr 9, 2007, 2:20:05 PM4/9/07
to
Richard Maine wrote:
...

> I need to use a temp variable to get the effect. First, I claim that
> introducing an intermediate variable cannot change the standard's
> claim that transfer((transfer(e,d),e) must return E. If that made a
> difference, then that would mean that the result of transfer was
> somehow not captured in its value. [...

What's "not captured in its value" mean? TRANSFER operates
on representations, not values.

> ...] In particular, if we change it to


>
> d = transfer(e,d)
> now use transfer(d,e)

Assignments operate on values, not internal representations.
Unless the rules of assignment are *required* to preserve the
internal representation, there's no reason to expect this to work.
For many types, like INTEGER for example, there's no reason
that assignment wouldn't preserve internal representation as well
as value (there's usually only one representation of any particular
value). But, the standard doesn't *require* the internal representation
to be preserved. The description of TRANSFER doesn't claim that
an intermediate assignment would preserve the identity in question.
It doesn't mention assignments at all.

...


> This is for a case where D is of a "benign" type where the assignment
> operator doesn't do anything "odd".
>
> So do
>
> d = transfer(e,d)
> call sub(transfer(d,ee),e)
>
> where ee is another vairiable of the same type as e. I probably don't
> even need it, but I use it to remove any question that the first
> argument might have any reference to e. Now in the subroutine
>
> subroutine sub(ee,e)

Let's rephrase this. Suppose P and Q are pointers to the type of
E. And suppose somewhere in the program you wrote:

P => E

And suppose elsewhere you write:

Q => P

and the elsewhere you write

call sub(Q, E)

If SUB doesn't define, redefine, or cause to become undefined either
of its arguments, this is still safe. Otherwise you're in violation of
the aliasing rule. But that's the same rule you'd violate with your use
of TRANSFER. So, it's not TRANSFER the introduces any potential
difficulty you see here, it's our old nemesis aliasing. The fact that
you've gone through contortions to prevent the compiler from actually
detecting the aliased value doesn't change that.

> [...] In particular, the actual arguments


> aren't associated in any way acknowledged by the standard, so the
> prohibitions against changing the values of the dummies don't apply.

Now you've *got* to be kidding! Under your hypothesis (that the
intervening assignment doesn't change internal representations) they
both refer to the same underlying entities. The rule about aliasing
don't say anything about the entities being associated in *acknowledged*
ways! If you change the entity, you can only reference the entity through
that one dummy argument. That's regardless of how the entities are
associated. The word "associated" isn't even used!

>> For
>> all we know, someone in the F90 committee carefully thought
>> through all possible cases and found no "havoc" arising from
>> any of them.
>
> You have *GOT* to be kidding. :-) Yes, I saw that you labelled it as
> speculation. But I don't even think it is very plausible speculation.

Well, given the shallow analysis so far in this thread, it's certainly
*very* plausible that F8x people pursued it much further that we
have. There were lots more of them and they tended to be more
zealously suspicious than the current committee seems to be.

> I've seentoo much of the committee close up; I don't think they would
> have thought through all the cases of that one, particularly as...
>
>> That's speculation too (unless someone remembers
>> it). It seems as likely as that there *is* a problem with the
>> requirement that no one can identify after all these years.
>
>
> "All these years" isn't very many for allocatable components, which
> are where I can most readily see a related problem. Wouldn't surprise
> me if there are others, but that's one I think I can see concretely.

I still don't see any problem. You have done enough hand wringing
that there *might* be a problem. But no *new* problem has been
evident (only ones due to other violations of the standard not related
to the use of TRANSFER). Your example still does nothing different
than CALL SUB(E, E) would do in the same circumstances. Your
attempt to characterize it as an unacknowledged form of association
doesn't change anything.

James Giles

unread,
Apr 9, 2007, 2:31:20 PM4/9/07
to
Richard Maine wrote:

> [...] then copying the same bits


> to another location doesn't preserve their meaning.

Exactly the point I made last time: TRANSFER deals with
internal represenatations while assignment (and most other
features of the language) deal with values. There's no
requirement that operations on values must preserve
representations.

Pointers and garbage collect are a good case in point.
Another reason that your assumption that an intermediate
assignment should be considered fair use of the TRANSFER
identity we've been talking about is just wrong.

glen herrmannsfeldt

unread,
Apr 9, 2007, 3:55:30 PM4/9/07
to
Richard Maine wrote:

(snip)

> In some senses, I'm not sure this is as good an example of problems as
> the allocatable one. But this is one that I actually got bit (um, pun
> not intended, or even noticed until I reread this) by in the early 90's.
> It is what made me start thinking about the possibility of cases where
> just naively copying the bits might not have the effect of copying all
> the information correctly. One example that occurred to me (but I don't
> think I've seen) would be relative addressing of pointers. If you have
> relative addressing, then copying the same bits to another location
> doesn't preserve their meaning.

There is an old trick of to save memory for doubly linked lists,
I believe sometimes used in C programs. Instead of storing the
two pointers (next and previous list element) you instead store
the exclusive OR of the two. In traversing the list, you know where
you are coming from, exclusive OR that with the stored value gives
the pointer to the next element. I would probably use the difference
instead, but then you need to know which direction you are going.

Neither are legal in standard C. Pointer comparison and subtraction
are only allowed on pointers to the same object, such as different
array element. A pointer difference chain would be legal within an
array, but not for separately allocated elements.

Assuming relative pointers are legal Fortran, it would seem to
exclude bit copying.

-- glen

glen herrmannsfeldt

unread,
Apr 9, 2007, 7:15:32 PM4/9/07
to
Richard Maine wrote:
(snip)

> "All these years" isn't very many for allocatable components, which are
> where I can most readily see a related problem. Wouldn't surprise me if
> there are others, but that's one I think I can see concretely. There's
> no way that whoever wrote the transfer description for f90 could have
> carefully considered how it worked with allocatable components, the
> details of which weren't done til a decade later.

Some of the subtleties should be similar to those for pointers.
Not all, I agree, but if the effect can be seen for pointer
components it shouldn't be attributed to allocatable components.

> I was there during all
> of the work on allocatable components, and I don't recall any such topic
> relating to transfer ever having been broached. I do recall that
> allocatable components had lots and lots of subtleties that took a long
> time to work out, both in the standard and in implementations.

-- glen

Ken Fairfield

unread,
Apr 9, 2007, 6:34:05 PM4/9/07
to
Richard Maine wrote:
> Brooks Moses <bmoses...@cits1.stanford.edu> wrote:
>
>> Richard Maine wrote:
[...]

>> Would it be allowable, at least, for a compiler to throw an error and
>> refuse to compile "transfer(transfer(-5_8, L), -5_8)" at all?
>
> I think you could argue that. But then you might get users who
> considered it a poor quality of implementation; that one is harder. I
> have trouble imagining why anyone would ever want to do such a strange
> thing, but James Buskirk can probably come up with something useful. :-)

I'd be one of those who thought is was poor quality of implementation!

I expect TRANSFER to very much be a replacement for EQUIVALENCE,
similar to the remarks of Mike Metcalf in this thread. It is
perfectly standard-conforming to equivalence integer, logical, real
and complex entities. Now the standard says that assigning to
one member of an equivalence list makes reference to any of the others
be undefined, IIRC. But it doesn't say anything about zero-ing out
"unused" bits in the logical member after assignment to the real or
integer member, etc.

I most emphatically agree with other comments in this thread that
conversions done by assignment should NOT be done by TRANSFER. That
would sort of defeat it's whole raison d'etre, wouldn't it?

-Ken
--
Ken & Ann Fairfield
What: Ken dot And dot Ann
Where: Gmail dot Com

FX

unread,
Apr 9, 2007, 6:55:24 PM4/9/07
to
> I'd be one of those who thought is was poor quality of implementation!

Then, the user bears the responsability to do only legitimate things, for
a definition of "legitimate" that is not documented by the standard.

Do you agree with this consideration, that you could transfer a value
into a logical variable L such that when calling the following code:

subroutine foo(L)
logical, intent(in) :: L
if (L) print *, "Test1"
if (.not. L) print *, "Test2"
end subroutine foo

could print neither Test1 nor Test2? (ie none of the IF is triggered)

--
FX

James Giles

unread,
Apr 9, 2007, 6:59:07 PM4/9/07
to
FX wrote:
>> I'd be one of those who thought is was poor quality of
>> implementation!
>
> Then, the user bears the responsability to do only legitimate things,
> for a definition of "legitimate" that is not documented by the
> standard.

Yes, that seems to me the whole purpose of TRANSFER.

Richard Maine

unread,
Apr 9, 2007, 7:25:58 PM4/9/07
to
glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:

> Richard Maine wrote:
> (snip)
>
> > "All these years" isn't very many for allocatable components, which are
> > where I can most readily see a related problem. Wouldn't surprise me if
> > there are others, but that's one I think I can see concretely. There's
> > no way that whoever wrote the transfer description for f90 could have
> > carefully considered how it worked with allocatable components, the
> > details of which weren't done til a decade later.
>
> Some of the subtleties should be similar to those for pointers.
> Not all, I agree, but if the effect can be seen for pointer
> components it shouldn't be attributed to allocatable components.

The ones that kept allocatable components from getting into f95, that
required corrections in the TR, and that have made it take a long time
for vendors to actually get allocatable components working are not in
common with pointers. That is to say, pretty much all the points that
I'd count as particularly subtle. I've been using pointer components
reliably for a decade and a half now. I don't have any production code
at all that uses allocatable components because last time I checked,
many of the compilers still had bugs in that area.

Ken Fairfield

unread,
Apr 9, 2007, 7:47:55 PM4/9/07
to

Yes, I agree (although I would probably avoid a system that
behaved that way).

glen herrmannsfeldt

unread,
Apr 9, 2007, 10:04:44 PM4/9/07
to
FX wrote:
(snip)

> Do you agree with this consideration, that you could transfer a value
> into a logical variable L such that when calling the following code:

> subroutine foo(L)
> logical, intent(in) :: L
> if (L) print *, "Test1"
> if (.not. L) print *, "Test2"
> end subroutine foo

> could print neither Test1 nor Test2? (ie none of the IF is triggered)

I would guess more likely it would print both, but neither would
also seem possible. If non-zero is true, and .NOT. complements
all bits, then it is easy to see that both L and .NOT.L could
be .TRUE..

-- glen

Pierre Asselin

unread,
Apr 10, 2007, 10:03:55 PM4/10/07
to
Michael Metcalf <michael...@compuserve.com> wrote:

> Well, it's 21(!) years ago, but my notes on the Halifax meeting in 1986
> include:

> "Transfer function

> [ ... ] I rewrote the proposals in the form of a single

> function able to return either scalar or array-valued results, depending on
> a MOLD argument. This was accepted 20-4. This function would allow us [the
> HEP community] to replace code of the form

> COMMON//Q(10000)
> INTEGER IQ(1)
> EQUIVALENCE (IQ,Q)
> :
> PX = Q(IQ(L) + 3)

> by

> COMMON//Q(10000)
> :
> PX = Q(TRANSFER(Q(L), 0) + 3) ! second argument moulds Q(L) to an
> ! integer scalar"

That lets you read the content of Q(L) as a integer value, but how
were you going to put the integer value in there in the first place ?
The old equivalence-based code would say

IQ(L)= index

but how do you express the same thing with TRANSFER ? If you try

Q(L)= TRANSFER(index, 0.0)

you are passing the converted value through an assignment. The
result of TRANSFER could be a denormal and its bits could be altered
before they went into Q(L).

TRANSFER provides a type-punning PEEK functionality, but where's
the POKE ?


--
pa at panix dot com

Jan Vorbrüggen

unread,
Apr 20, 2007, 4:04:20 AM4/20/07
to
> One example that occurred to me (but I don't
> think I've seen) would be relative addressing of pointers.

If you use queues with sharing in potentially different address spaces, they
will only work if the pointers they contain are relative addresses. That is
how these are implemented in the VAX ISA. So yes, they do exist.

Jan

Jan Vorbrüggen

unread,
Apr 20, 2007, 4:39:52 AM4/20/07
to
> Do you agree with this consideration, that you could transfer a value
> into a logical variable L such that when calling the following code:
>
> subroutine foo(L)
> logical, intent(in) :: L
> if (L) print *, "Test1"
> if (.not. L) print *, "Test2"
> end subroutine foo
>
> could print neither Test1 nor Test2? (ie none of the IF is triggered)

Yes.

On the other hand, I think using an integer-sized storage unit to store a
logical value, and to then define a representation for the logical value that
gives no interpretation to most of the values this representation can take, a
mistake. Why not go the DEC way and just interpret the LSB as the value of the
logical, instead of explicitly comparing the whole value to 0 and 1?

Jan

Jan Vorbrüggen

unread,
Apr 20, 2007, 4:45:19 AM4/20/07
to
> Assignment is an different question. The question asked about the
> transfer intrinsic itself - not about assignment of its result. Those
> are *NOT* the same thing. A function result can be used without
> assigning it.

Indeed. I am interpreting James Giles's position as saying that the standard
defines that

X = TRANSFER(TRANSFER(Y,I),X)

be equivalent to

X = Y

while

I = TRANSFER(Y,I)
X = TRANSFER(I,X)

would not necessarily do so, precisely because the second case contains an
additional assignment statement that is not covered by the section of the
standard under discussion.

While a plausible interpretation, I think the hair being split here as being
too fine, and together with Metcalf's meeting notes fom 21 years ago, I do
think that this was not the intent of the committee when it wrote that passage.

Jan

james...@att.net

unread,
Apr 20, 2007, 1:04:11 PM4/20/07
to
On Apr 20, 2:45 am, Jan Vorbrüggen <jvorbrueg...@not-mediasec.de>
wrote:
...

> Indeed. I am interpreting James Giles's position as saying that the standard
> defines that
>
> X = TRANSFER(TRANSFER(Y,I),X)
>
> be equivalent to
>
> X = Y
>
> while
>
> I = TRANSFER(Y,I)
> X = TRANSFER(I,X)
>
> would not necessarily do so, precisely because the second case contains an
> additional assignment statement that is not covered by the section of the
> standard under discussion.
>
> While a plausible interpretation, I think the hair being split here as being
> too fine, and together with Metcalf's meeting notes fom 21 years ago, I do
> think that this was not the intent of the committee when it wrote that passage.

So that means this obscure (and not even explicitly stated) property
of
TRANSFER actually places constraints on the pragmatics of assignment
(and other issues)?

I find this thread a little unsettling since I'm in the position of
defending
a feature that I don't like at all: TRANSFER. There's little that I
find well
defined or desirable about the description of that intrinsic. In
fact, the
particular identity that's the subject of this thread was the only
entirely
sensible and well defined part of the feature. That's assuming you
treat
it as a clarification of the fact that the same bits are moved in each
direction (without any "normalization" or other changes) and not as a
prescription for something anyone might want to actually do.

TRANSFER has all kind of problems.

It too verbose.

It's too flexible. No one really needs to copy the bits for *any*
type to
*any* other type (the usual is to transfer from some type to which
the
bit operations can't be applied to a type where they can be applied,
do some bit ops, and transfer back).

Certainly TRANSFER shouldn't be allowed to apply to types containing
POINTER or ALLOCATABLE components. People will do that anyway:
implementations will provide the "extension" (ie. not enforce the
constraint).
But the language shouldn't provide a *standard* way to reverse
engineer
such descriptors.

TRANSFER is not well defined: it says the "leading parts" of the data
are
moved into the "leading parts" of the destination type. By direct
observation
of the several implementations I have easiest access to, the "leading
parts"
(at least of INTEGER and REAL types) are the least significant bits.
Yet,
many on the committee (rather emphatically) believe the "leading" bits
of
such objects to be the *most* significant bits. So much so that they
insist
there's no mnemonic difficulty with naming some new intrinsics LEADZ
and TRAILZ (I know they are vehement about this because I suggested
in another forum that LEFTZ and RIGHTZ would be better choices).

And now you're claiming that the identity specified in the definition
of
TRANSFER requires that *assignment* of, say, float decimal can
normalize.
Or that garbage collect can't move POINTER and ALLOCATABLE associated
data because things not currently recognizable as having such
attributed
might still have bits whose meaning is such descriptors. And all the
other
problems mentioned in this thread. Well, at least that makes it a
clean
sweep: there's nothing at all to like about TRANSFER.

Jan Vorbrüggen

unread,
Apr 25, 2007, 9:10:48 AM4/25/07
to
> So that means this obscure (and not even explicitly stated) property of
> TRANSFER actually places constraints on the pragmatics of assignment
> (and other issues)?

Which obscure and not even explicitly stated property are you taking about -
the identity cited from the standard text, or Metcalf's meeting notes on the
subject?

> Certainly TRANSFER shouldn't be allowed to apply to types containing
> POINTER or ALLOCATABLE components.

Agreed.

> And now you're claiming that the identity specified in the definition
> of TRANSFER requires that *assignment* of, say, float decimal can
> normalize.

Where did I do that?

I think I offered an interpretation that did not restrict the semantics of
assignment, precisely because the identity as written does not require this,
as the two items involved are of identical type anyway.

However, if the intent was for the "split" form of the identity, with the
intermediate assignment, to function nonetheless, _then_ this would impose a
requirement on an implementation to _not_ normalize, range-check or otherwise
process the bits during, at least, this particular kind of assignment, i.e.,
with TRANSFER on the RHS.

Jan

james...@att.net

unread,
Apr 26, 2007, 1:41:53 AM4/26/07
to
On Apr 25, 7:10 am, Jan Vorbrüggen <jvorbrueg...@not-mediasec.de>
wrote:

> > So that means this obscure (and not even explicitly stated) property of
> > TRANSFER actually places constraints on the pragmatics of assignment
> > (and other issues)?
>
> Which obscure and not even explicitly stated property are you taking about -
> the identity cited from the standard text, or Metcalf's meeting notes on the
> subject?

The latter. Though I was operating under the assumption that you
were
accepting his recollection as the proper meaning of the former.

> However, if the intent was for the "split" form of the identity, with the
> intermediate assignment, to function nonetheless, _then_ this would impose a
> requirement on an implementation to _not_ normalize, range-check or otherwise
> process the bits during, at least, this particular kind of assignment, i.e.,
> with TRANSFER on the RHS.

That would really be bad. I don't like rules where the semantics of
one thing
(like assignment in this case) would depend on some special case.
Assignment
of a given type of value to a given type of variable should not be
dependent on
*where* that value came from.

Jan Vorbrüggen

unread,
Apr 26, 2007, 6:09:51 AM4/26/07
to
>>Which obscure and not even explicitly stated property are you taking about -
>>the identity cited from the standard text, or Metcalf's meeting notes on the
>>subject?
> The latter. Though I was operating under the assumption that you were
> accepting his recollection as the proper meaning of the former.

OK. I was more in the "Talmudic argument" mode, but I certainly consider his
recollection as conveying the _intended_ meaning of the text in the F90 standard.

>>However, if the intent was for the "split" form of the identity, with the
>>intermediate assignment, to function nonetheless, _then_ this would impose a
>>requirement on an implementation to _not_ normalize, range-check or otherwise
>>process the bits during, at least, this particular kind of assignment, i.e.,
>>with TRANSFER on the RHS.
> That would really be bad. I don't like rules where the semantics of one thing
> (like assignment in this case) would depend on some special case. Assignment
> of a given type of value to a given type of variable should not be dependent on
> *where* that value came from.

Quite agreed. I used it as a strawman argument to show that this
interpretation seems unreasonable.

Thus, we are left with the situation that the original intent (see above) does
appear unreasonable.

Jan

Pierre Asselin

unread,
Apr 26, 2007, 11:34:05 AM4/26/07
to
james...@att.net <james...@att.net> wrote:
> On Apr 25, 7:10 am, Jan Vorbr?ggen <jvorbrueg...@not-mediasec.de>
> wrote:

> > However, if the intent was for the "split" form of the identity, with the
> > intermediate assignment, to function nonetheless, _then_ this would impose a
> > requirement on an implementation to _not_ normalize, range-check or otherwise
> > process the bits during, at least, this particular kind of assignment, i.e.,
> > with TRANSFER on the RHS.

> That would really be bad. I don't like rules where the semantics of
> one thing (like assignment in this case) would depend on some special
> case. Assignment of a given type of value to a given type of variable
> should not be dependent on *where* that value came from.

Agreed. This makes TRANSFER essentially useless since the transferred
value can't be saved anywhere. Or to put it another way, the type
punning enabled by TRANSFER is read-only. *If* a bit pattern
meaningful for type MOLD has already been placed in SOURCE by
implementation-dependent means, then TRANSFER(SOURCE,MOLD) can read
it back. Unfortunately the only legal way to make the bits is for
SOURCE to itself be a TRANSFER expression; not too useful.

It seems to me we need another intrinsic. Can we overload
TRANSFER itself ?

TRANSFER(source,mold,[size])
! intrinsinc function, as now

TRANSFER(source,[size],DESTINATION=variable)
! intrinsic subroutine,
! uninterpreted bit copy without assignment conversions

If DESTINATION= is supplied, TRANSFER becomes an intrinsic subroutine
rather than a function. There is no need for a mold and there is
no returned value. If size is omitted, it defaults to the smaller
of the source and destination sizes. This would supply the missing
functionality while staying close to the intent documented in Mike's
notes.

It would be odd to have an intrinsic that is both a function and
a subroutine, but vendors could implement it as an extension without
wrecking the language (I think). It could be standardized later,
assuming people still have a use for it.

Then we can ask again how to transfer derived types with allocatable
components :-)

james...@att.net

unread,
Apr 26, 2007, 3:31:49 PM4/26/07
to
On Apr 26, 9:34 am, p...@see.signature.invalid (Pierre Asselin) wrote:
...

> It seems to me we need another intrinsic. Can we overload
> TRANSFER itself ?

Well I know people are tired of hearing this (since it's a hobby and
I have no expectations that it'll ever be released for public use),
but in my language there is a feature that addresses this. All
intrinsic types except integers (for reasons that will be obvious)
have a "representation component" notation. That is, you can
apply a component selector similar to what extracts a field of
a derived type to variables or named constants of intrinsic type.
In a Fortranified notation, this would look like:

x%as_int = ior(x%as_int,1)

If X is, say, default real this statement will set the bit of it that
corresponds with the least significant bit of an integer. I mention
this case since at one time I had a program that had to make
sure the significant of a float value was odd. Obviously if j is
an integer variable j%as_int is still just j, so I don't allow the
syntax for integers.

Now the rule is that x%as_int turns into an integer KIND that's
at least as big as the storage required by x (whatever type it
is). This does mean that Fortran would have to introduce a
new integer KIND (at least one) large enough to hold the bits
of the largest supported REAL KIND. If X is smaller than the
integer KIND it gets treated as, the bits of X occupy the least
significant bits of the integer value, the rest are zeros. If an
integer expression on the right of an assignment is larger than
X, the least significant bits of the value become the new bits
of X and the rest are ignored.

COMPLEX variables cannot use this syntax directly since I
regard COMPLEX as a derived type (a built-in one, but still
a derived type). A COMPLEX variable (or named constant)
already has two components: R and I. So, if Z is COMPLEX,
you can say Z%R%as_int or Z%I%as_int.

Character values used here must have a length of one. I tried
all kind of ideas to get around that. Consistent syntax is
possible, but always confusing. So, if X is a string (of length
more than one) you'll have to do something like X(j:j)%as_int.
If Fortran had strings of types other than character, and if
strings were considered to be a variety of array rather than
as scalars, this would not be so hard.

If a procedure dummy argument is declared to be INTEGER of
some KIND, the actual argument may be X%as_int, for any
type X might be provided that the rule I gave above would be
the same KIND of integer. The obvious thing happens if the
dummy argument is INTENT(OUT) and gets modified in the
procedure: the bits of X are redefined on return from the procedure
(similar rules as for assignment if X is of different size than
the integer KIND it got associated with).

Since this applied to intrinsic types only, and since POINTER
and ALLOCATABLE are attributes, not types, it simply isn't
even possible for the internal representations of the descriptors
of such things to be manipulated by this feature at all.

This pretty much covers all the uses I've ever had for TRANSFER-
like operations. It's easier to read, less verbose, and I like
it lots better than the new BIT data type F2008 will probably contain.
There's probably no likelihood Fortran will ever adopt it. The
new BIT type will probably do what you want without the extra
complexity of your TRANSFER-destination idea. BIT brings a
lot of complexities of its own to the table.

0 new messages