-
Notifications
You must be signed in to change notification settings - Fork 17
First draft of run-time polymorphism proposal #143
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
Conversation
This is great. Thanks. I do have few questions, to which I hadn't devised good answers myself yet.
or would one need to "compose" a new interface from the two and provide that name as done in the examples you give?
I feel like this might only possible with compile time stuff like templates, but wondered if you had any ideas. |
Thank you for submitting this! @tclune what is your opinion on this? |
@everythingfunctional So far I have thoughts on your first two points, so let's focus
So, your example of
which brings us to the next point: this is a nasty circular reference ( I personally believe that it will be essentially impossible, in any OO application code of some complexity, to entirely avoid circular references. But we want their occurrence to be among interfaces only. We don't want them to occur among concrete implementation types, and we sure don't want them to occur between interfaces and types that depend on them. Unless I am missing something, I believe we need to check in detail how this has been dealt with in Rust. |
Rust has a way of referring to the "Implementation" type inside a trait block. The keyword I think with that additional specification you could solve both my situations like
and
We may need to think through all the implications that will have on inheritance though. For example, inside an interface block that inherits from another, does that mean referring to any of those traits that way means the actual type implementing that trait? Probably. But what about abstract and extended types? If I create an abstract type that "implements" a trait, but defers implementation of some of the procedures, in the extended type, when implementing the necessary procedures, do arguments of I think we can probably define the spec well enough to handle this, just trying to make sure we think through all the edge cases. |
My next question is then about "generics", and brings up the question about which argument is Say I want to implement a something like
|
I have another thought related to this, but that should probably be a follow up proposal. What about a library that defines a trait, and another library that defines a type, but I'd like to be able to use them together? In Rust this is possible because the implementation of a trait is separate from the definition of the type, and can be done in multiple places. Would it be possible in Fortran to allow types to be "re-opened" so as to add procedures in a different place? Maybe not, and we'll just have to stick with wrapper types for that use case, but it may be worth considering. |
@everythingfunctional Ok, I believe I got your point. I think you mean that we need to have a pair of names: "trait"/"class" for abstract interfaces in the same way as we have "type"/"class" for derived types (unfortunately the most logical pair: "abstract interface"/"trait" is out of the question due to its verbosity). Hence the confusion with the names. Yes, I agree. The whole thing needs to be modelled with respect to inheritance essentially in the same way as type/class is for derived types. I need to check in detail the Rust link that you provided to understand how they did it, and to see whether we should add some example along these lines to the proposal. |
@everythingfunctional To comment on your last question first. I believe it should be possible to do in Fortran what is done in Rust. Fortran and Rust are very similar in that they do not have classes in the sense of Java or C++. They only have "structures" (structs in Rust, types in Fortran) to which procedures are bound. Therefore, I believe it should be possible, in principle, to make the proposed feature a complete equivalent to Rust's |
@certik , is there anybody on any of the major compiler teams active on here that may be able to speak to this? @difference-scheme , there was a suggestion not to require types to specify which traits they implement, just have the compiler verify it at each use. I think that would probably slow down compile times. But it probably would enable more flexibility. |
I have revised the proposal to account for @everythingfunctional's feedback. I have opted to admit only one way for declaring polymorphic variables, namely Fortran's standard way, using the class specifier (which would therefore need to be extended). I believe anything else will lead to confusion. I have also added a Java and a Rust version of the (Fortran) example code given in Appendix B of the proposal. You can find them in the separate Examples directory, in case you'd like to see how the proposed features work in these languages. |
@certik Unfortunately, I couldn't find the time before the committee's upcoming meeting next week to make the present proposal as complete as I'd like it to be. What is presently missing is a facility like Kotlin's Will the present version of this proposal, along with #142, be nevertheless discussed in the upcoming committee meeting? |
@difference-scheme I think it is good enough to be discussed. I think in general the committee prefers a simple text file, instead of a pdf, but I could be wrong on that. Either way, since this will not go into 202X, I think we do not perhaps need to submit this formally, but simply discuss it as an option for generic programming in the Data subcommittee. (I personally think we should do it more like Rust does it, and do most of generic programming at compile time, not runtime. If I find time, I'll try to submit a separate proposal along those lines. But it's good that your idea got written down, so that we can discuss it and move the discussion forward.) |
@certik Thanks for your reply. Could you elaborate briefly on what features you think should be taken from Rust? To my knowledge, Rust offers both compile-time generics, and run-time polymorphism (the latter by using "trait-objects"), so I would think that these two do not conflict with each other. Of course, anything that can be done at compile time should be done right then and there (at zero run-time cost). |
I think you are right --- I am still learning Rust and I am currently not 100% sure what happens at runtime and what happens at compile time, but it seems Rust has both compile-time generics, and run-time polymorphism, and the traits seem to be actually used for both (https://blog.rust-lang.org/2015/05/11/traits.html). Anyway, your proposal moves the conversation forward and may end up as part of the big proposal for generics. I am very happy that we are moving forward on these things. |
Yes, in Rust the traits are used for both the bounding of compile-time generics, and for enabling subtyping run-time polymorphism. This is why having named abstract interfaces in Fortran would be so important; it would serve both these purposes. We really need to have both these capabilities in the language, because they are complementary: some things that can be done with run-time polymorphism cannot be done with compile-time generics, and vice versa. It would be a terrible blow to Fortran if we couldn't get both these capabilities into the language (and we need them rather sooner than later). So, I hope you will find the opportunity to work on the generics proposal, and I'd be willing to help out with this. |
I agree that we need both. I also agree we should design both at the same time.
I'll keep you updated.
…On Fri, Feb 21, 2020, at 4:38 PM, difference-scheme wrote:
Yes, in Rust the traits are used for both the bounding of compile-time
generics, and for enabling subtyping run-time polymorphism.
This is why having named abstract interfaces in Fortran would be so
important; it would serve *both* these purposes. We really need to have
*both* these capabilities in the language, because they are
complementary: some things that can be done with run-time polymorphism
cannot be done with compile-time generics, and vice versa.
It would be a terrible blow to Fortran if we couldn't get both these
capabilities into the language (and we need them rather sooner than
later). So, I hope you will find the opportunity to work on the
generics proposal, and I'd be willing to help out with this.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#143?email_source=notifications&email_token=AAAFAWH5S4XLTFBCTDOCJTLREBQXXA5CNFSM4KQPILZKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEMUOETA#issuecomment-589881932>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAAFAWH7MTDAMB44GLIBIPDREBQXXANCNFSM4KQPILZA>.
|
This PR would be a great reference for a proposal. A good proposal should be 75 characters per line and between 50 - 400 lines. Also, it should be written as a regular text file, not latex or pdf. As I said, I'll discuss this with the Data subcommittee and update this issue with the results. |
@certik: Any news on this? |
@difference-scheme yes, we discussed your proposal together with #125 The consensus so far seems to be that we want both runtime polymorphism (both #143 and #125 seem quite similar in this respect, obviously we would need to unify the syntax) as well as compile time polymorphism (the proposal #125 actually covers that too). It seems the way Rust handles Traits is something to consider, it might be exactly what we need. We discussed that the Rust syntax seems identical for compile time as well as runtime generics, and we were a bit unsure how Rust determines which one will happen. We should do more examples and analyze on case by case basis. More importantly, when considering features such as #157, a common objection at the plenary was that we really need to have a plan for generics (even if they would go into 202Y) so that we can ensure that such features such as #157 are designed to be consistent with generics, so that we do not end up with a not well thought out system. As such, I would like to push forward and hopefully get a community agreement how the generics should be done for 202Y, and then design features such as #157 for 202X to be consistent with them. |
@certik Thanks for the update! I agree that Rust handles traits in a very elegant and general way and that we should consider taking their approach as a baseline for both compile-time and run-time polymorphism. We shouldn't forget Swift, though, which does things in a manner that is very similar to Rust, and which has, moreover, succeeded in making all of this even interoperable with (classical) implementation inheritance. Personally, I wouldn't even mind declaring Fortran's implementation inheritance, introduced in the 2003 standard, an obsolescent feature, if we would have a Rust-equivalent of run-time/compile-time polymorphism as an alternative. So, I believe we should be bold/progressive. Do you think that there might be opposition in the committee to such a progressive design, by people that would prefer a more conservative path? Concerning Rust's run-time vs. compile-time generics see also the following overview: |
@difference-scheme great link, thanks for sharing it. I personally wouldn't mind at all to make inheritance obsolete, and to recommend Rust style composition using Traits instead, as long as there is a clear path how to upgrade. But even if it is not officially obsolete, we can still, as a community, simply recommend to use traits over inheritance. Magne stressed a lot to try to implement Traits with similar syntax as what is already in Fortran, to make it more familiar to users as well as perhaps easier to implement for compilers. |
@certik I fully agree (also with Magne's point). Rust-style composition combined with automatic (implicit) delegation (as in Kotlin) is a way better programming model than inheritance. Also, implicit delegation will be absolutely crucial for easing the programmers' transition from the use of inheritance towards the use of the new features, so it is something we will absolutely need to have. Rust doesn't have it yet, because they couldn't agree so far on a sufficiently simple implementation: rust-lang/rfcs#2393 It would be nice to see Fortran being quicker in this respect! |
@difference-scheme good point about delegation. If you have some ideas how to design it for Fortran, please open an issue / PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am approving the pull requent because @certik assigned it to me. But I do feel that this work is going into specs when we do not even have a general agreement on requirements. I'm going to work hard to have a requirements paper ready for the WG5 meeting and would encourage others to contribute clear use cases (for this and other aspects of generics).
@certik I have some first ideas on how delegation could be done in Fortran, in order to make it an almost drop-in replacement for implementation inheritance. I had started to work on an update of the present proposal along these lines, because I thought implicit delegation would be best explained in this same context (to demonstrate its use on the same examples so that one may clearly judge its benefits). But since the present proposal appears to have been merged some moments ago, would you like me to keep updating this one, or should I open a new PR (along with an accompanying issue) that deals exclusively with delegation? |
@difference-scheme go ahead and open a new PR that deals with delegation. @tclune thanks for the input. Note that I assigned it before the meeting, in the hopes that we can merge and discuss more ahead of time before we meet in person. In the same spirit, I would encourage that if you come up with requirements, that you share it with us well ahead of the meeting, so that we can discuss and think about it, in order to be more efficient in person. See also #163. I believe that in order to come up with good requirements, we need to have an initial informal proposal in hand first. |
This proposal resulted from the discussion in Issue #125. It accounts for some of the suggestions made there, but includes also some (minor) new twists. It motivates why Fortran's run-time polymorphism needs to be strengthened, and includes a use case to demonstrate the advantages of the proposed features.