j3-fortran / fortran_proposals

Proposals for the Fortran Standard Committee
173 stars 14 forks source link

Allow setting default value for optional dummy argument #22

Open milancurcic opened 4 years ago

milancurcic commented 4 years ago

Problem

Currently, Fortran doesn't allow setting a default value for optional dummy arguments. If declaring a dummy argument as optional, the user must:

  1. Manually make appropriate checks about whether the actual argument is provided by the caller;
  2. Use a separate variable inside the procedure because the code must not reference the optional dummy argument if not present.

Example

Example of a quadratic function that optionally allows evaluation of its linear form:

real function quadratic(x, a, b, c)  
  ! returns a + b * x + c * x**2 if c is present and a + b * x otherwise
  real, intent(in) :: x, a, b
  real, intent(in), optional :: c
  real :: c_tmp ! use separate variable to avoid referencing non-present arg
  if (present(c)) then
    c_tmp = c
  else
    c_tmp = 0 ! default value if c is not present
  end if
  quadratic = a + b * x + c_tmp * x**2
end function quadratic

Checking for presence of the optional argument and using a temporary variable is cumbersome and error-prone, and it is even more so if the same needs to be done for many optional arguments.

Solution

Allow setting the default value of the optional argument in the function (or subroutine) statement by using the assignment operator =:

real function quadratic(x, a, b, c=0)
  ! returns a + b * x + c * x**2 if c is present and a + b * x otherwise
  real, intent(in) :: x, a, b
  real, intent(in), optional :: c
  quadratic = a + b * x + c * x**2
end function quadratic

This is similar to how Python keyword arguments are defined.

Comments

certik commented 4 years ago

Yes, great idea. I usually do it like this:

real function quadratic(x, a, b, c)  
  ! returns a + b * x + c * x**2 if c is present and a + b * x otherwise
  real, intent(in) :: x, a, b
  real, intent(in), optional :: c
  real :: c_
  c_ = 0
  if (present(c)) c_ = c
  quadratic = a + b * x + c_ * x**2
end function quadratic

Which is simpler than your original code, but it's still cumbersome to always introduce the local variable and do the present(c) check.

Does Fortran support default non-optional arguments? My only suggestion would be to perhaps introduce default values for any arguments, not just optional.

milancurcic commented 4 years ago

What is the meaning of default non-optional arguments? If an argument is required, where does its default value come into play?

certik commented 4 years ago

What is the meaning of default non-optional arguments? If an argument is required, where does its default value come into play?

My bad, I think you are right. It only makes sense for optional arguments.

certik commented 4 years ago

The other suggestion I have is that in Fortran one specifies all argument things in the declaration, not in the argument list so perhaps something like this:

real function quadratic(x, a, b, c)
  ! returns a + b * x + c * x**2 if c is present and a + b * x otherwise
  real, intent(in) :: x, a, b
  real, intent(in), optional, default :: c = 0
  quadratic = a + b * x + c * x**2
end function quadratic

Would be more consistent with Fortran conventions.

The new default attribute would specify that the = 0 does not imply the save attribute. The default attribute can then be used with any variable, not just arguments, like this:

integer, default :: n = 5

Perhaps one could use init, or initialize instead of default.

milancurcic commented 4 years ago

I like the default attribute. Less Pythonic, but more Fortranic for sure.

Of course, I had to use the more verbose variant to better sell the proposal. :D

certik commented 4 years ago

I like the default attribute. Less Pythonic, but more Fortranic for sure.

The proposal can have both options, and the community and committee can discuss pros and cons of both, and then pick one.

Of course, I had to use the more verbose variant to better sell the proposal. :D

I would suggest you change it to the shorter version, as we want to compare against the best current practice, not a longer variant.

milancurcic commented 4 years ago

I'd be happy to prepare the first draft of the proposal, and you can take it from there. Does target for meeting #221 (February 2020) make sense?

certik commented 4 years ago

I'd be happy to prepare the first draft of the proposal, and you can take it from there. Does target for meeting #221 (February 2020) make sense?

Yes! The October Committee Meeting ended, and what I would like to do differently than what the committee has been doing so far, is to prepare a very good proposal collaboratively on GitHub. Send a PR once you have a draft, let's work on it together and with others. And then once a good initial proposal is ready, I'll pitch it to the j3-members committee mailinglist, to get feedback from the committee, and that way we have a very solid proposal when the committee meets the next time and we'll take it from there. Finally, I would reiterate my invitation for you to join the committee. We need help.

certik commented 4 years ago

This should be implemented in the language. It's a simple change and it would go a long way. In the meantime, we will implement a helper function in stdlib: https://github.com/fortran-lang/stdlib/issues/62, here is a preliminary implementation: https://github.com/fortran-lang/stdlib/pull/73. The above example would look:

real function quadratic(x, a, b, c)  
  ! returns a + b * x + c * x**2 if c is present and a + b * x otherwise
  real, intent(in) :: x, a, b
  real, intent(in), optional :: c
  real :: c_
  c_ = optval(c, 0.)
  quadratic = a + b * x + c_ * x**2
end function quadratic

Which is not bad, but not as nice as having it in the language:

real function quadratic(x, a, b, c)
  ! returns a + b * x + c * x**2 if c is present and a + b * x otherwise
  real, intent(in) :: x, a, b
  real, intent(in), optional, default :: c = 0
  quadratic = a + b * x + c * x**2
end function quadratic

Note: in this particular case, since we need c exactly once, one can simplify it with stdlib to just:

real function quadratic(x, a, b, c)  
  ! returns a + b * x + c * x**2 if c is present and a + b * x otherwise
  real, intent(in) :: x, a, b
  real, intent(in), optional :: c
  quadratic = a + b * x + optval(c, 0.) * x**2
end function quadratic

but this does not work well if c is needed more than once.

sblionel commented 4 years ago

This proposal got some votes in the user survey for 202X, and it is one I personally like. It appeared on Data subgroup's wishlist at meeting 215 (see https://j3-fortran.org/doc/year/18/18-122r1.txt) https://j3-fortran.org/doc/year/18/18-136r1.txt with "use cases" was passed at meeting 216, but it didn't make it onto the "official" US request list - it's not clear to me if this was an oversight or the lack of a formal proposal. In either case, I would support this for 202Y.

zbeekman commented 4 years ago

I too support this.

certik commented 4 years ago

Ok, let's write a good proposal for this and submit for the February meeting (#122) to get initial feedback from the committee. As indicated at #122, the following people listed this proposal in their top 5: @milancurcic, @epagone, @zjibben, @qolin1. The following people mentioned it that they like it to be pursued: @jvdp1, @marshallward. And there are people who expressed support here directly, such as @zbeekman and others who liked the issue.

@milancurcic would you be able to take a lead on writing a proposal for this? The others listed in this comment, if you could help Milan write it, that would be very helpful. (I'll try to help too, but there are other proposals that I want to help with also.)

qolin1 commented 4 years ago

Yes I am in.

While we are here, I have some questions & comments...

Firstly, why should the DEFAULT keyword be needed? Seems to me that the mere presence of an equated value after the variable name will be sufficient, as in:

real function quadratic(x, a, b, c)
! returns a + b * x + c * x2 if c is present and a + b * x otherwise
real, intent(in) :: x, a, b
real, intent(in), optional :: c = 0
quadratic = a + b * x + c * x2
end function quadratic

As far as I am aware, there is currently no way the language will allow an equated value for a variable declared as a dummy argument, so this seems sufficient to me. Also, providing a new keyword like DEFAULT might mislead folk into trying to put it on non-optional arguments and other (local variable) declarations. (If the intention is to distinguish this from the implicit save problem, then the name DEFAULT is not a good one, because it doesn't really mean "do not save". And I think we should keep this proposal well clear of any argument about implicit save.) Also also, when 2 or more arguments are declared in one statement, we would not wish to require them all to be given a default value, or none of them; this would be the implication of the presence of the DEFAULT keyword.

Second: do we allow the default value to change a simple variable into an array? Eg:

Subroutine fred(a,b)
real, intent(in) :: a
real, intent(in), optional :: b = [1d0,2d0]

Note that, absent the default, there is nothing in the declaration of B that makes it an array. IMO this should not be allowed, explicit shape information or the DIMENSION keyword should be required.

Third: should the feature work for UDTs? Eg:


type t_stuff
real :: a = 22
real :: b = 33
real :: c = 44
end type
subroutine uu(ff, st)
real, intent(in) :: ff
real, optional :: st = t_stuff(66,c=88)

Fourth: should it work on an OPTIONAL statement? eg:

Subroutine fred(a,b)
real, intent(in) :: a, b
optional :: b = [1d0,2d0]

Fifth: what about allocatables? eg:

Subroutine fred(a,b)
real, intent(in) :: a
real, intent(in), allocatable, optional :: b(:) = [1d0,2d0]

This creates a default allocated array with 2 elements. I can't, however, see an obvious way to get an unallocated array as a default. Maybe it could be done by combining with the next one...

Sixth: should it allow initialization to a non-constant expression? eg:

module jimmy
real :: ddd(100)
end module
! ...lots of lines of code later, after ddd has been set
subroutine billy(aaa,bbb)
use jimmy
real, intent(inout) :: aaa(20)
real, intent(inout), optional :: bbb(:) = ddd

...That's probably more than enough for the moment.

milancurcic commented 4 years ago

@milancurcic would you be able to take a lead on writing a proposal for this? The others listed in this comment, if you could help Milan write it, that would be very helpful. (I'll try to help too, but there are other proposals that I want to help with also.)

Sure, I will submit an initial draft in a PR later this week and we can iterate on it together.

certik commented 4 years ago

@qolin1 thanks a lot for the feedback. Excellent ideas. Here are my comments.

  1. I think you are right, we don't need the default. Yes, I put it there to ensure no save, but as you said, the save would not be implied in this case anyway. I really like just this, exactly as you suggested:

    real function quadratic(x, a, b, c)
    ! returns a + b * x + c * x2 if c is present and a + b * x otherwise
    real, intent(in) :: x, a, b
    real, intent(in), optional :: c = 0
    quadratic = a + b * x + c * x2
    end function quadratic
  2. No.

  3. Yes.

  4. Yes. I didn't even know about an optional statement.

  5. Yes.

  6. I would say to start with requiring the expression to be constant. We can brainstorm if it makes sense for it to be variable. It seems it could create more confusion than it is worth it.

epagone commented 4 years ago

@qolin1 these are my thoughts.

  1. I agree with you and @certik on this one but I already hear the objection that the same syntax in different scoping units meaning different things (i.e. implicit save in some contexts and optional default values in this case) should not be allowed. My best reply would be to deprecate in parallel implicit save with proposal #40. However, this carries the risk that if #40 is shot down, then also this one can be refused, so maybe a better strategy to respond to this objection must be thought...

  2. Should not be allowed, as you suggest.

  3. Yes.

  4. Yes.

  5. I don't fully understand what is the problem you're discussing here. I think

    Subroutine fred(a,b)
    real, intent(in) :: a
    real, intent(in), allocatable, optional :: b(:) = [1d0,2d0]

    should be allowed with b allocated by default to [1d0,2d0] but it would be possible to set in subroutine fred b = [1d0,2d0,3d0,4d0,5d0] (i.e. fixed shape but any size, since b is an allocatable array).

  6. I understand @certik 's concerns about this but I think it should be allowed.

certik commented 4 years ago

Regarding 1.: Note that, as I mention in #40, that "One can apparently use integer :: a, b, c = 2 in the main program, in module variable and in derived types already, and it will not imply save." So this proposal #22 just adds another case: "in optional arguments it will also not imply save". So it's not unprecedented even if #40 is not (immediately) accepted.

P.S. @milancurcic make sure you use this argument in the proposal.

epagone commented 4 years ago

@certik I was looking for the fingers crossed emoji to be added next to the thumb up as a reaction to your post, but it's not available on GitHub... 😜

sblionel commented 4 years ago

Any proposal should specify whether the default value may be a specification expression or must be a constant expression. The latter would be consistent with initialization, but the former would be more useful. Note that the rules for specification expressions already prohibit an object designator with OPTIONAL or INTENT(OUT).

Since a default value would be allowed only for optional arguments, that implies an explicit interface requirement.

qolin1 commented 4 years ago

Um Steve, Please clarify for us what is meant by an "object designator". If we have an example default initialization such as:

real, intent(out), optional :: aa = b+c*d

My understanding is that b, c and d are object designators, but aa is not. Please correct me.

sblionel commented 4 years ago

Sorry, was quoting the standard regarding specification expressions. In your example, b, c and d are the object designators in question. The issue is what is allowed to appear in the default value expression. If it's a specification expression, it can reference things such as other dummy arguments and module variables. If it's a constant expression, it is restricted to only those things that can be evaluated at compile-time, which is the case for initialization. (Indeed these used to be called "initialization expressions".)

The more details worked out in advance for a proposal, the better chance it has to move forward. One can even propose edits (ideally including complete new wording to make it easier to understand and read.)

What I envision for this is that the caller could evaluate and pass the default values, since it already needs to know how to do this for some specification expressions.

zjibben commented 4 years ago

The proposal is now submitted:

https://j3-fortran.org/doc/year/20/20-107.txt

Thank you all and especially @milancurcic and @jvdp1 for kicking off the proposal!

milancurcic commented 4 years ago

Thank you all for pushing it through!

On Sun, Feb 23, 2020, 1:05 PM Zach Jibben notifications@github.com wrote:

The proposal is now submitted:

https://j3-fortran.org/doc/year/20/20-107.txt

Thank you all and especially @milancurcic https://github.com/milancurcic and @jvdp1 https://github.com/jvdp1 for kicking off the proposal!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/j3-fortran/fortran_proposals/issues/22?email_source=notifications&email_token=AA7RDPUTA5BA3CY6I5XYO3DREK3HNA5CNFSM4JCMOXG2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEMWC4JA#issuecomment-590097956, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA7RDPSLGCH7LLOVSL2F77LREK3HNANCNFSM4JCMOXGQ .

certik commented 4 years ago

This proposal was discussed on Tuesday Feb 25 in the morning, I set the timer for 5 minutes, @zjibben gave an overview for about 3 minutes and then we discussed for about 20 minutes at the plenary. We took notes of the feedback and I summarized it below.

Overall, we got excellent highly detailed feedback, and I would say the committee was generally positive about the idea. The approach suggested might not work directly, but the committee suggested an alternative approach that might work. Also lots of details must be figured out and fleshed out, and the proposal must be rewritten / improved accordingly.

Here is the detailed feedback. I tried to summarize it first, but not all the comments are necessarily consistent, so I simply present the comments:

To summarize, the issue is that we do not want to change the behavior of present(). But then the issue is that it becomes really complicated if the user provides the value high in the call chain, then the nested subroutines might change how they behave, thus potentially creating performance bottlenecks.

The best way forward seems to be not to tie the default value with optional arguments. Rather, to introduce “initial” (or “default”) attribute that can be applied to both local variables, as well as dummy variables. If applied to dummy variables, it would have no change in the subroutine itself --- the dummy argument would always be provided. However, at the call site, the compiler would put in the default value if the user does not provide it. That way there is no performance hit, and from the user perspective it achieves the same.

milancurcic commented 4 years ago

Amazing, this is great feedback, I didn't expect that we'd get this much. Thanks @certik and @zjibben.

I think we can work with this. I will take some time to digest and write what I think.

zjibben commented 4 years ago

Thanks for polishing the notes and posting @certik!

certik commented 4 years ago

@milancurcic indeed, it went really well. We have done another one (#1) today, and in general I think we will be doing this from now on. So this is a great avenue how to have a discussion with the wider community and how the community can propose ideas for the language.

jvdp1 commented 4 years ago

Thanks @certik and @zjibben for presenting and leading the discussion, and reporting back the discussion. It is really encouraging.

wclodius2 commented 4 years ago

I have written a revision of the paper by @milancurcic, @jvdp1, and @zjibben that attempts to address most of the issues raised at the Feb. 25 meeting, and a few other issues that have come to my mind. The paper differs from the original primarily by:

  1. Restricting optional arguments to arguments with the INTENT(IN), VALUE, or no intent attributes.

  2. Requiring arguments with a default assignment to be explicitly given the DEFAULT attribute.

  3. Forbidding arguments from having both the DEFAULT and OPTIONAL attributes so that the PRESENT function retains its semantics.

  4. Allowing the expression on the right of the default assignment be a restricted expression and not just a constant expression.

  5. Strongly encouraging that the default assignment be in the FUNCTION or SUBROUTINE statement (and not the TYPE declaration statement) as probably being easier to parse.

  6. Discussing the implications of the constraints on intrinsic assignment, 10.2.1.2, their interpretation, 10.2.1.3, and the constraints on defined assignment, 10.2.1.4, and their interpretation, 10.2.1.5 on default array assignments.

  7. Briefly discussing the implications of an argument with the DEFAULT attribute also having any one of the POINTER, VOLATILE, ASYNCHRONOUS, or TARGET attributes.

sblionel commented 4 years ago

This sounds great - when can we see the paper? The changes you propose are all those I support.

wclodius2 commented 4 years ago

I am a novice to GitHub. The introductory material on GitHub does a good job of telling me how to start my own project, but not how to participate in someone else's project. What steps do I need to take to upload the paper named revised_proposal.txt?

milancurcic commented 4 years ago

William, great. If you navigate here:

https://github.com/j3-fortran/fortran_proposals/blob/master/proposals/default_optional_arguments/proposal.txt

In the upper right corner of the UI there is an "Edit" button. If you click on it, it will take you to an editor which you can use to replace the existing paper with yours. Submitting the change will open a new Pull Request in which we will then discuss and edit the revised version.

The above flow assumes that we edit existing proposal txt files. @certik @zjibben should we instead keep the old versions as separate files and add the new one in its own file (like J3 does)?

wclodius2 commented 4 years ago

FWIW I named my version revised_proposl.txt in the expectation that we would retain original, proposal.txt, for the records.

On Jul 10, 2020, at 3:05 PM, Milan Curcic notifications@github.com wrote:

William, great. If you navigate here:

https://github.com/j3-fortran/fortran_proposals/blob/master/proposals/default_optional_arguments/proposal.txt https://github.com/j3-fortran/fortran_proposals/blob/master/proposals/default_optional_arguments/proposal.txt In the upper right corner of the UI there is an "Edit" button. If you click on it, it will take you to an editor which you can use to replace the existing paper with yours. Submitting the change will open a new Pull Request in which we will then discuss and edit the revised version.

The above flow assumes that we edit existing proposal txt files. @certik https://github.com/certik @zjibben https://github.com/zjibben should we instead keep the old versions as separate files and add the new one in its own file (like J3 does)?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/j3-fortran/fortran_proposals/issues/22#issuecomment-656890414, or unsubscribe https://github.com/notifications/unsubscribe-auth/APTQDORHHFYI4SZXSHT3AGTR257CRANCNFSM4JCMOXGQ.

wclodius2 commented 4 years ago

FWIW trying to add a file at https://github.com/j3-fortran/fortran_proposals/tree/master/proposals/default_optional_arguments gives the message: Uploads are disabled. File uploads require push access to this repository.

certik commented 4 years ago

I am thinking of preserving the original paper, as the discussion is based on that. But let's have a dedicated directory for all the papers and documents related to this feature.

On Fri, Jul 10, 2020, at 3:05 PM, Milan Curcic wrote:

William, great. If you navigate here:

https://github.com/j3-fortran/fortran_proposals/blob/master/proposals/default_optional_arguments/proposal.txt

In the upper right corner of the UI there is an "Edit" button. If you click on it, it will take you to an editor which you can use to replace the existing paper with yours. Submitting the change will open a new Pull Request in which we will then discuss and edit the revised version.

The above flow assumes that we edit existing proposal txt files. @certik https://github.com/certik @zjibben https://github.com/zjibben should we instead keep the old versions as separate files and add the new one in its own file (like J3 does)?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/j3-fortran/fortran_proposals/issues/22#issuecomment-656890414, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAFAWFMV63Z2B7JFOA3NO3R257CPANCNFSM4JCMOXGQ.

wclodius2 commented 4 years ago

You already have such a directory https://github.com/j3-fortran/fortran_proposals/tree/master/proposals/default_optional_arguments the one I need push access to

milancurcic commented 4 years ago

William, here's what you need to do:

  1. Fork this repository by navigating to https://github.com/j3-fortran/fortran_proposals and clicking on "Fork" in the upper-right corner.
  2. You now have a fork here: https://github.com/wclodius2/fortran_proposals. Add your paper here: https://github.com/wclodius2/fortran_proposals/tree/master/proposals/default_optional_arguments (you will have push access to your fork of this repo).
  3. Now navigate back to https://github.com/j3-fortran/fortran_proposals. Near the top of the page there will be a UI element asking if you want to submit a Pull Request with the changes in your fork. Click on it, edit if needed, and click on "open pull request" (or similar, I forget the exact words).
wclodius2 commented 4 years ago

The revised_proposal.txt has been checked into the repository.

everythingfunctional commented 4 years ago

Just a comment. Keeping old files around with a naming convention for revisions kind of misses the point of having a version control system (the old versions can still be accessed if desired). But since not everyone interested in the project will be familiar with git, it's probably best to do it anyway.

certik commented 4 years ago

@everythingfunctional I think we should work on just one file and add changes to it (e.g. in https://github.com/j3-fortran/fortran_proposals/pull/175), but once we submit it to the J3 meeting for consideration, I think it's good to keep a copy around, so that you don't have to go into git history all the time to see what the original was that the J3 discussion is based upon.

wclodius2 commented 4 years ago

FWIW I have changed how the proposal discusses arguments with no intent. Instead of assuming that such arguments will be treated the same as INTENT(IN) or VALUE, I call no intent out separately and note how the wording in the standard should be phrased to either treat them the same as INTENT(IN) or VALUE or treat them like INTENT(INOUT) or INTENT(OUT).

wclodius2 commented 4 years ago

My revised proposal was that default values are relevant for dummy arguments with INTENT(IN) or VALUE explicity specified. It originally had no intent as an option, but consistently repeating “INTENT(IN), or, VALUE, or no intent” was awkward, and there was the problem that many people assume the no intent was,ery similar to INtENT(INOUT). It did not propose to “automatically” give some different attributes to no intent arguments. Users would have to explicitly give the DEFAULT attribute, and write out the DEFAULT assignment.

On Jul 25, 2020, at 9:12 PM, septcolor notifications@github.com wrote:

I was assuming that the default value is relevant only for dummy arguments with INTENT(IN) explicitly specified. On the other hand, if the dummy arguments with no intent are automatically given some different attributes in future (say, intent(OUT) or VALUE), doesn't it mean that it silently breaks existing codes? (For example, INTENT(OUT) deallocates allocatable dummy arrays automatically, while VALUE changes the semantics from pass-by-reference to pass-by-value (in practice), which is crucial for foreign language interface.

I guess it would already be extremely useful to be able to specify the default value for only the case where INTENT(IN), VALUE is explicitly specified, while no default value is allowed otherwise. At the moment, I need to use PRESENT() and declare additional local variables to set the default value, which is very inconvenient (as compared to other languages).

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/j3-fortran/fortran_proposals/issues/22#issuecomment-663930058, or unsubscribe https://github.com/notifications/unsubscribe-auth/APTQDOVDYPMAWERFPLL6Q3TR5ONLBANCNFSM4JCMOXGQ.

jvdp1 commented 3 years ago

Just to remember that a revised version of the proposal is in the MR: #175 . It doesn't appear clearly in this thread...

vansnyder commented 3 years ago

During the development of Fortran 90, back when it was still called Fortran 8x, there was a proposal for an AUTOMATIC attribute. When RECURSIVE was added, the argument was that every variable that isn't SAVE is automatic. The standard's definition of "automatic variable" was needlessly narrowed to one that used a variable to specify a bound or length parameter. I no longer have records from that time; I sent them to the Computer History Museum. Loren Meissner is the curator for them.

Had the AUTOMATIC attribute been retained, an obvious definition of AUTOMATIC with initialization would have meant automatic initialization, not SAVE. Specifying the AUTOMATIC attribute without initialization would simply confirm what we already say now. Explicitly specifying AUTOMATIC and SAVE for a particular variable should be prohibited. Explicitly specified AUTOMATIC would override default SAVE. AUTOMATIC would naturally be prohibited for storage-associated variables.

Once AUTOMATIC is defined that way, all that is necessary to provide default values for absent optional arguments is to define an absent OPTIONAL argument that has initialization to be a local automatic variable.

The PRESENT intrinsic should still be available to inquire whether there was an associated actual argument. Even if there's a value for a local variable acting in lieu of the absent dummy argument, it's still useful to know whether the actual argument was present.

Youjunhu commented 2 years ago

"Same syntax as Python keyword args, so it would be intuitive to Python developers learning Fortran;"

"keyword argument" is only relevant when you call a function. The definition of a function does not care which argument will be called with the arg=value style. The correct word should be "default argument".

ivan-pi commented 1 year ago

C++17 has introduced a class template std::optional that can be used to pass or return optional values and obeys value semantics.

An example of passing an optional value to a subroutine looks as follows:

#include <iostream>
#include <optional>

void display(std::optional<int> opt_a) {
    if (opt_a) {
        std::cout << "a is present with value " << *opt_a << '\n';
    } else {
        std::cout << "a is not present" << '\n';
    }
}

int main() {

    auto a = std::make_optional<int>(42);
    display(a);
    display({});

    return 0;
}

To supply a default non-null value you could modify the prototype:

void display(std::optional<int> a = {42})

The class template also has an accessor method value_or which can be used to return the contained value if available and another value otherwise, e.g.

int a = opt_a.value_or(42)

This is kind of similar to the the Fortran-lang stdlib function optval. An attempt to define a Fortran operator in similar spirit called .presentOr., that could be used as

integer :: c_
c_ = c .presentOr. 42.   ! present(c) ? c : 42

fails since the argument of an operator interface cannot be optional.

Sandwich-X commented 1 year ago

variants:

real, intent(in), optional, default(0.0) :: c real, intent(in), optional(0.0) :: c