-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Protected Components #156
Comments
@zjibben can fill in the details. It looks like the latest version so far has a requirement that a protected component (meaning one cannot write into it from outside the class) will require that one cannot assign the class variable to another ( I am personally against that, I don't think that's a good approach. If using the equivalence of |
C++ does have |
As @certik said, there is something in the works related to #16, but the existing version has many more restrictions than we expected. In particular, if you have a type with a protected component (or some subobject which ultimately has a protected component), there are many things you wouldn't be able to do outside the module where it is defined. The restrictions which raised concern were, outside the module where the type containing a protected component defined, you could not allocate or deallocate a variable of the type, nor use intrinsic assignment to the object as a whole if it contains a protected data member ( Some committee members were concerned this would make protected components too unwieldy to use in practice, that they shouldn't add more write-restrictions than private components, and protected components shouldn't have so strong an affect on how the object itself is used. They would force a lot of boiler plate to use defined assignment or type extension or allocatables if all a programmer wanted was automatic and free getter methods. On the other hand, the counter-argument is that without these restrictions you aren't really protecting the data all that much. Anyone outside the module could blow it away with a reallocation or intrinsic assignment to the variable which ultimately contains protected data. We agreed the restriction on type extension was too far, so that is going away. The rest is up for debate. At the moment things are leaning toward reworking the requirements entirely, that the original version may be too heavy a hammer, but I think nothing is really settled one way or another. |
If memory serves, you can use intrinsic assignment on derived types with private components, so I don't see why anything should be different for types with protected ones. |
@zjibben , @certik: Similar to @cmacmackin, I also think, that members with protected attribute should behave the same way as private members do, with the only notable difference, that reading them shall be also allowed in routines outside of the module with the type declaration. |
Reading through the attached documents I got the impression, that the protected attribute should receive even more "protection" as private components (e.g. protected components can never change, unless a routine in the module defining the type is invoked). I think, this is unnecessarily strict, as not even private members have that protection:
As explained above, I'd suggest to treat protected data componenets on a similar foot as private ones, with the exception of allowing protected data components to appear as rvalue in expressions outside of the defining module. The protectedness of a data member should not cause any more restriction for the given type, as a private data member does. |
As for type extension: The extended type should inherit the protected data component of the base type. (In contrast to private components, which are "invisible" in extending types). If the extending type is defined in a different module as the base type, though, it would only be able to manipulate the protected data component via routines defined in the module of the base type. (Similarly, how an extending type needs the setter routines of the base type in order to manipulate its private components.) I may have, of course, overseen something trivial, and I am definitely lacking the experience and far-sigthedness of the committee members. But I think, that by interpreting the protected data members as just a kind of light version of private components, we could add the desired functionality (reading out values directly, without the need of getter routines) with minimal side effects. |
Thank you all for the feedback, these are exactly the points I've brought up with the committee. I sat down with them to write up a toy example to depict what I (and I think others here) would like, which includes intrinsic assignment for one. This was the example: module foo_type
implicit none
type :: foo
real, protected :: a
real, private :: b
contains
procedure :: init
end type foo
contains
subroutine init(this, x)
class(foo), intent(out) :: this
real, intent(in) :: x
a = x
b = -x
end subroutine init
end module foo_type
program main
use foo_type
implicit none
type(foo) :: f, g
real :: x
x = 1
call g%init(x)
f = g ! We want to be able to do this.
! Now it is not possible to insert garbage in f%a,
! without changing f%b
end program main The counter-example which shows the danger they're concerned about is here, using a linked list: ! Linked list mock-up
module bar_type
implicit none
type :: bar
type(bar), pointer, protected :: prev => null()
type(bar), pointer, protected :: next => null()
contains
procedure :: init
end type bar
contains
subroutine init(this)
class(bar), intent(out) :: this
this%prev => this
this%next => this
end subroutine init
end module bar_type
program main
use bar_type
implicit none
type(bar) :: f, g
call g%init()
f = g
! Now f has pointers to g instead of itself, so is a
! linked list that can't get back to itself.
! Committee solution is forbid intrinsic assignment.
end program main The argument coming from some in the committee is that intrinsic assignment can produce things you don't want, so why do it? If you want assignment, make a defined assignment within the module where the type is defined. I might argue that this danger seems limited to linked-list type situations and not particularly damaging (existing data is intact, new object is undesired). So, we might instead have a programmer write defined assignment to override (=) when they want to prevent intrinsic assignment rather than make it impossible for all the objects where it's actually preferred. But at this point I believe we are at an impasse of conflicting interests, and most likely the "forbid intrinsic assignment, allocation, and deallocation" version will go through. |
Exactly the same thing could happen if you used private components for |
It seems that the proposal attempts to take "protected" absolutely literally. I'll just echo what everyone else is saying, that we want something just a bit less restrictive than |
This is exactly the problem as I see it, and as a result it looks like we're getting something that protects data so tightly that it can't be used for much. There are workarounds, like having defined-assignment which just turns around and does the intrinsic assignment within the module where the type is defined. But at that point, it's a lot of boiler plate for what it's giving you. As a consequence of this protection, it was realized that At any rate, my reading of the committee is this will go a very different direction than what most developers (including myself) are interested in. |
My understanding is that the Data subcommittee couldn't agree on the way forward, so decided not to put the proposal for a vote tomorrow. |
Oh, that's quite sad news! Anyway, if some more arguments are needed: I think, the case of the linked list structure, which was used to justify the complicated behavior, is not a very good one. Usually, if one implements a container, one wants to hide the implementation details (whether it is a linked list or not) completely and provides iterators instead. So trying to make a linked list safe from unnoticed changes should not the object to aim for. What we should aim at instead is to protect consistency of data within one derive type instance without any kind of warranty for the "ethernal" existence of the derived type instance. (Exactly as the language already does it for private components...) As a compromise, why not splitting the efforts into two parts?
And one last note, as pointers were mentioned: A pointer having the Anyway @certik @zjibben thanks a lot for all your efforts, and let's see, whether we still have to provide getters in twenty years.... |
Ok, so after a long discussion in the Data subcommittee, the current proposal would require the developer of the class A with protected components to provide the type bound assignment operator, but if they do, then as the user, you can assign So I think, at least from a user perspective, you can use |
Finally, as @zjibben mentioned, the automatic deallocation would still work intuitively. Just explicit deallocation would not work. Allocation would need to be done with a subroutine that the module developer provides (actually by overloading the constructor, so this would also work intuitively). (Explicit allocation from outside the module would not work.) |
I still don't understand what the reason is for treating protected
components more strictly than private ones.
…On Thu, 27 Feb 2020, 18:48 Ondřej Čertík, ***@***.***> wrote:
Finally, as @zjibben <https://github.com/zjibben> mentioned, the
automatic deallocation would still work intuitively. Just explicit
deallocation would not work.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#156?email_source=notifications&email_token=AB6ESPKNMCUULCU6EQQYTZ3RFADJJA5CNFSM4K3WKLZKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOENFP4BQ#issuecomment-592117254>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AB6ESPNXWOR2KS72IHSTI5DRFADJJANCNFSM4K3WKLZA>
.
|
Unfortunately I don't understand why either... @zjibben, @klausler, @FortranFan, @everythingfunctional are sitting in the same room --- is any of you able to answer @cmacmackin's question? |
This has to do with the example above protecting pointers, and existing expectations from the term |
Visibility of components and definability of components are being treated as independent concepts, which (IMO) they are. |
The conclusion reached in the Data subcommittee so far is that we have to bring lots of use cases. That is, code that we would like to work with "protected". Then at our next meeting, we will sit down and see how to make them work with the proposal. |
I think the initial idea expressed here was meant to be, relax the restrictions of private, without allowing for direct assignment/change of the component. Instead the committee is defining protected as "disallow all ways of modifying the value of this component, except from procedures within the defining module". |
I just learned there is an older proposal which describes a version of https://j3-fortran.org/doc/year/18/18-265.txt There, intrinsic assignment is allowed, and allocation and deallocation aren't called out at all. I think this is the paper to reference in future use cases, along with @aradi's paper. |
@cmacmackin wrote:
I'm still struggling to understand the underlying technical reasons, but my understanding is this paper - https://j3-fortran.org/doc/year/19/19-135r1.txt - forms the basis for much of the rationale. As stated in some of the recent posts above, my understanding is the "protected" attribute of derived type components as being currently for Fortran 202X refers to what can appear in a "variable definition context". It is the not accessibility relative to module scope as it is applied to PUBLIC/PRIVATE attributes. |
I think, I know where some of the confusions comes from (at least mine). I have always interpreted the
So, as @klausler pointed out, the visibility and definability are indeed independent from the view point of the current standard. And this is probably, what the committee tries to apply to the derived type components as well. (Which means, the |
I think that's precisely it!
However, I think what most people want instead is something like private, but read only and visible.
…On Thu, Feb 27, 2020, at 11:43 PM, Bálint Aradi wrote:
I think, I know where some of the confusions comes from (at least
mine). I have always interpreted the `protected` attribute in modules
as a visibility between `private` and `protected` and wished to
transfer it to derived type components as well. But reading Modern
Fortran Explained (and probably the standard says the same) about the
`protected` attribute:
> This attribute does not affect the visibility of the variable, which must must still be public to be visible, but confers the same protection aginst modification that intent `ın` does for dummy arguments.
So, as @klausler <https://github.com/klausler> pointed out, the
visibility and definability are indeed independent from the view point
of the current standard. And this is probably, what the committee tries
to apply to the derived type components as well. (Which means, the
`protected` attribute would be an additional one on top of the `public`
attribute of a component).
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#156?email_source=notifications&email_token=AAAFAWBSX6GOYTOQCNMLZWDRFC6BHA5CNFSM4K3WKLZKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOENHSVWY#issuecomment-592390875>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAAFAWGR2YS3HANOO4R3PFLRFC6BHANCNFSM4K3WKLZA>.
|
In order to be in accordance with the spirit of the current standard, we just have to make sure, that
This would probably give exactly the expected user experience and would be still in accordance with the spirit of the standard. |
The paper https://j3-fortran.org/doc/year/20/20-121.txt was withdrawn after a discussion and general opposition to it. A way out that was suggested is to implement protected components along the lines of the paper https://j3-fortran.org/doc/year/18/18-265.txt, which would satisfy what people in this thread expect. Then in addition, there could be a protected class, which would restrict even the assignment and other things. The protected component and protected class would be two different features. |
The committee overall seemed to understand the concerns expressed over the usability of the feature as proposed, and was very agreeable to withdrawal. |
That's quite good news. I was not aware of https://j3-fortran.org/doc/year/18/18-265.txt, but it seems to formulate exactly the same idea as suggested above and would be in accordance with the original proposal on GitHub! So, there is still hope! 😉 |
Because the semantics of |
Everyone, I have a new specs & syntax paper over at #182 planned for the next meeting (Oct 12). Please take a look & comment your suggestions. |
@zjibben, @certik, and everyone contributing here, Kudos on great effort and collaboration. With the However I am simply unable to understand the Thus an immediate question and a suggestion: will it be possible to break up the |
As part of #155, the committee is looking at protected components as part of
US 19 Protected Components
https://j3-fortran.org/doc/year/18/18-265.txt
https://j3-fortran.org/doc/year/19/19-135r1.txt
https://j3-fortran.org/doc/year/19/19-161.txt
https://j3-fortran.org/doc/year/19/19-214r1.txt
https://j3-fortran.org/doc/year/20/20-106.txt
https://j3-fortran.org/doc/year/20/20-121.txt
The text was updated successfully, but these errors were encountered: