- 신규로 표시
- 북마크
- 구독
- 소거
- RSS 피드 구독
- 강조
- 인쇄
- 부적절한 컨텐트 신고
Dear all,
there is an issue, I've found with user defined assignment when using the ifort compiler (version 16.0). Let's have a basic type with user defined assignment (as TBP) and an extending type which does not define its own assignment. When a non-polymorphic instance of the extended type is defined, an assignment to it invokes the user defined assignment of the base type. When I understood the explanations of Malcom Cohen (as response to my nagfor compiler bug report in this matter), this should, however, not happen. So, in the example below, the assignBasic() routine should not be invoked (as it happens in the ifort compiled binary).
module typedef
implicit none
type :: Basic
contains
procedure :: assignBasic
generic :: assignment(=) => assignBasic
end type Basic
type, extends(Basic) :: Extended
end type Extended
contains
subroutine assignBasic(this, other)
class(Basic), intent(out) :: this
type(Basic), intent(in) :: other
print "(A)", "assignBasic invoked"
end subroutine assignBasic
end module typedef
program test
use typedef
implicit none
type(Extended) :: ext
print "(A)", "Non-polymorphic assignment"
ext = Extended()
end program test
링크가 복사됨
- 신규로 표시
- 북마크
- 구독
- 소거
- RSS 피드 구독
- 강조
- 인쇄
- 부적절한 컨텐트 신고
Thank you for the report. I'll investigate and route to Development.
(Internal tracking id: DPD200414314)
- 신규로 표시
- 북마크
- 구독
- 소거
- RSS 피드 구독
- 강조
- 인쇄
- 부적절한 컨텐트 신고
I think the behaviour is subject to interp F08/0146.
The issue is that the `other` dummy argument of the subroutine implementing defined assignment is not polymorphic, not the polymorphic/non-polymorphic nature of the thing being assigned. When it is not polymorphic, that `other` dummy argument, which is of type `Base`, is not type compatible with a right hand side object of type Extended. Consequently the overall assignment on line 32 is intrinsic.
But the process of intrinsic assignment invokes defined assignment for components of the type. Depending on F08/0146, this includes the parent component, which is of type `Base` and is therefore type compatible with the `other` dummy argument.
I think it makes little sense for the language to not consider defined assignment for the parent component ahead of subcomponents of that parent component i.e., I hope the result of the interp is such that you should see "assignBasic invoked". As a principle, objects of derived type should not break up into their components if there is the possibility of operating on the object as an aggregate.
- 신규로 표시
- 북마크
- 구독
- 소거
- RSS 피드 구독
- 강조
- 인쇄
- 부적절한 컨텐트 신고
As always, Ian can formulate the problem much more accurate, than I. Ian, I really appreciate your capability to reformulate my confusing explanations to a clear statement about the real problem. :-)
Just out of curiosity: The interpretation you refer to (the one you hope for), has that been already decided on in any form? Or is it something which is still being debated? Just because from the answer I got from Malcom Cohen, I had the feeling, he wants to point out explicitely, that intrinsic assignment is done nonancestor-componentwise, so assignBasic should not be invoked in the example above. But I'd for sure find your interpretation more satisfying, provided I can rely on the fact, that all compilers do it the same way.
- 신규로 표시
- 북마크
- 구독
- 소거
- RSS 피드 구독
- 강조
- 인쇄
- 부적절한 컨텐트 신고
F08/0146 is still being considered. It failed its initial meeting vote in October 2015. I can't find any indication it has been reconsidered since then.
- 신규로 표시
- 북마크
- 구독
- 소거
- RSS 피드 구독
- 강조
- 인쇄
- 부적절한 컨텐트 신고
I routed the case and extended comments to Development.
- 신규로 표시
- 북마크
- 구독
- 소거
- RSS 피드 구독
- 강조
- 인쇄
- 부적절한 컨텐트 신고
For everyone's information, here's the content of interp F08/0146 including committee member Tom Clune's view of "how it should work", which Malcolm Cohen of NAG disagrees with. This is likely to be revisited at next month's meeting.
NUMBER: F08/0146
TITLE: Does intrinsic assignment copy inherited components twice?
KEYWORDS: Intrinsic assignment, Type extension
DEFECT TYPE: Erratum
STATUS: J3 consideration in progress
QUESTION:
Consider
Type base
Integer a
End Type
Type,Extends(base) :: ext
Real b
End Type
...
Type(ext) x,y
...
x = y
According to 7.2.1.2 Intrinsic assignment statement, p13,
"An intrinsic assignment where the variable is of derived type is
performed as if each component of the variable were assigned from
the corresponding component of <expr>"
This would seem to indicate that the above assignment "x = y" is
interpreted as the following (in unspecified order):
x%a = y%a
x%b = y%b
x%base = y%base
and the assignment to x%base is treated as if it were
x%base%a = y%base%a
thus assigning to x%a twice, which does not seem to make sense. If a
type is extended more than once, there can be a plethora of ancestor
components inheritance-associated with a component, resulting in that
component being assigned many times.
Q1. Are these per-component assignment semantics intended to apply to
ancestor components (and thus produce multiple assignments for
inherited components).
It is particularly problematic if the components have type-bound
defined assignment, for example consider the program
Module damod
Type datype
Contains
Procedure asgnda
Generic :: Assignment(=) => asgnda
End Type
Contains
Subroutine asgnda(a,b)
Class(datype),Intent(Out) :: a
Class(datype),Intent(In) :: b
Print *,'Hello asgnda'
End Subroutine
End Module
Module types
Use damod
Type base
Type(datype) c
End Type
Type,Extends(base) :: ext
End Type
End Module
Program test
Use types
Type(ext) :: x = ext(datype()), y
y = x
End Program
Q2. Does this program print "Hello asgnda" once or twice?
ANSWER:
A1. This sentence was not intended to apply to ancestor components; an
edit is supplied to correct this oversight.
A2. The program should print "Hello asgnda" only once.
EDITS to 10-007r1:
[156:3] 7.2.1.2 Intrinsic assignment statement, p13,
Between "performed as if each" and "component"
insert "nonancestor".
SUBMITTED BY: Malcolm Cohen
HISTORY: 15-218 m208 F08/0146 Submitted
m208 Failed J3 meeting vote 3-4
<< start of Tom Clune's comments on F08/0146>>
expect defind assignment to work like finalization on the parent
of an extended type [15-007r2 4.5.6.2 78:19] - if the parent has
defined assignment, it is called on the parent and not on its components.
From: Tom Clune
Sent: Friday, October 16, 2015 9:41 AM
Attached below is a motivating example of my objection to the interp
we discussed on Tuesday. (Paper 218 I think.)
I also have a few additional arguments to bolster my case:
1) If I understand correctly, the semantics of finalization work on
the base object, not on the components of the base object. In
15-007r2.pdf 4.5.6.2 The finalization process (78:19), we have:
"If the entity is of extended type and the parent type is
finalizable, the parent component is finalized."
The proposed interp seems to run contrary to this treatment of the
base as a coherent entity.
2) Not that it really matters, but C++ implicit copy/assignment semantics
also use the copy/assignment operator for the base object, not its
components.
3) Just to reiterate my point on Tuesday. The proposed interp in 218
adds considerable burden to implementors of type extensions. If a
base type overrides default assignment, then the type extension
almost certainly must as well, or risk ruining some invariant property
that the base otherwise preserves. Further, this burden propagates
down the inheritance hierarchy. Perhaps on some occasions, the
implementor may find that default assignment is actually ok, but it
would require looking "inside" the base type implementation. (And I
cannot construct a plausible motivating example of this situation,
though I've also not tried very hard.)
! The following is an example of how many users intuitively expect
! instrinsic assignment of an extended type when the ancestor type
! has a derived assignment.
! Here, we desire _deep_ copy semantics for type base, which happens to
! use POINTER components. In this instance, an allocatable component
! could fix the issue, but consider the case of a base type which
! implements a binary tree, and pointer components were thus much harder
! to avoid.
module the_classes
type :: base
integer, pointer :: ptr => null()
contains
procedure :: equals
generic :: assignment(=) => equals
end type base
! We now extend the base class in a relatively trivial manner.
! There needs to be at least one new component or the casual
! observer might think that the assignment defined below
! could just use CLASS for the RHS argument and allow inheritance
! to do the "right thing" (TM). Often we would like the new components
! defined in the extension to be copied as well, and that
! approach becomes inadequate.
type, extends(base) :: child
character(len=:), allocatable :: name
end type child
contains
subroutine equals(a, b)
class (base), intent(out) :: a
type (base), intent(in) :: b
allocate(a%ptr)
a%ptr = b%ptr
end subroutine equals
end module the_classes
program main
use the_classes
implicit none
type (child) :: c1, c2
allocate(c1%ptr)
c1%ptr = 1
c1%name = 'Alice'
c2 = c1
! Because we want "deep copy" semantics, we want to be able to change
! c1%ptr without impacting c2
c1%ptr = 2
print*,'Results:'
print '(10x,a10,1x,i1)', c2%name, c2%ptr
print '(a9,1x,a10,1x,i1)', 'Expected: ','Alice',1
end program main
<<end of Tom Clune's comment on F08/0146>>
- 신규로 표시
- 북마크
- 구독
- 소거
- RSS 피드 구독
- 강조
- 인쇄
- 부적절한 컨텐트 신고
Steve Lionel (Intel) wrote:
For everyone's information, here's the content of interp F08/0146 including committee member Tom Clune's view of "how it should work", which Malcolm Cohen of NAG disagrees with. This is likely to be revisited at next month's meeting.
NUMBER: F08/0146 TITLE: Does intrinsic assignment copy inherited components twice? .. This would seem to indicate that the above assignment "x = y" is interpreted as the following (in unspecified order): x%a = y%a x%b = y%b x%base = y%base and the assignment to x%base is treated as if it were x%base%a = y%base%a thus assigning to x%a twice, which does not seem to make sense. ..
But, Steve, what about "Inheritance association" (16.5.4 in WD 1539-1 J3-10-007r1 document for Fortran 2008)?
8 16.5.4 Inheritance association 9 1 Inheritance association occurs between components of the parent component and components inherited by type 10 extension into an extended type (4.5.7.2). This association is persistent; it is not affected by the accessibility of 11 the inherited components.
Doesn't inheritance association essentially imply there is really no such thing as "x%a", that it essentially only has "association" that is persistent with "x%base%a"? Therefore, isn't the assignment "x%a = y%a" meaningless, that it is only "x%base%a = y%base%a" which is relevant?
So how does the "twice" part of the question addressed by the interp even arise?