j3-fortran / fortran_proposals

Proposals for the Fortran Standard Committee
178 stars 15 forks source link

Revised version of the default arguments proposal #175

Open wclodius2 opened 4 years ago

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:

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

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

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

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

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.

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.

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

certik commented 4 years ago

Thanks for submitting this!

I like this. The only thing I am not sure is to specify the default expression in the subroutine statement. Indeed that is how other languages do that, but those languages also define the type there. In Fortran we define types separately from the subroutine line. So I think the default value should be initialized at the declaration also.

Note also that in your proposal the default keyword is redundant. If you remove it, you arrive at the initial proposal from Milan. See the discussion at the original issue.

On Sat, Jul 11, 2020, at 10:31 PM, William B. Clodius wrote:

I have written a revision of the paper by @milancurcic https://github.com/milancurcic, @jvdp1 https://github.com/jvdp1, and @zjibben https://github.com/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:

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

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

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

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

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.

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.

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

You can view, comment on, or merge this pull request online at:

https://github.com/j3-fortran/fortran_proposals/pull/175

Commit Summary

wclodius2 commented 4 years ago

OTOH I suspect that overriding the default assignment will normally be done by “assignment" to the named argument in the procedure call. The similarity to the usage I find attractive. I also find it very awkward attempting to distinguish between the constant assignment that gives the save attribute to local variables, and the proposed default assignment to arguments. The definition of an entity declaration in the TYPE declaration statement will become even more complex.

The DEFAULT keyword is redundant in the same sense that the OPTIONAL keyword is redundant. Fortran could have implicitly assigned the default attribute to any argument that is used with the PRESENT() function. I find the DEFAULT keyword very useful in distinguishing between arguments with the DEFAULT and OPTIONAL attributes. Redundancy isn’t always bad. See what happened to the SAVE attribute.

On Jul 11, 2020, at 10:59 PM, Ondřej Čertík notifications@github.com wrote:

Thanks for submitting this!

I like this. The only thing I am not sure is to specify the default expression in the subroutine statement. Indeed that is how other languages do that, but those languages also define the type there. In Fortran we define types separately from the subroutine line. So I think the default value should be initialized at the declaration also.

Note also that in your proposal the default keyword is redundant. If you remove it, you arrive at the initial proposal from Milan. See the discussion at the original issue.

On Sat, Jul 11, 2020, at 10:31 PM, William B. Clodius wrote:

I have written a revision of the paper by @milancurcic https://github.com/milancurcic, @jvdp1 https://github.com/jvdp1, and @zjibben https://github.com/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:

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

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

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

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

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.

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.

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

You can view, comment on, or merge this pull request online at:

https://github.com/j3-fortran/fortran_proposals/pull/175

Commit Summary

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/j3-fortran/fortran_proposals/pull/175#issuecomment-657175461, or unsubscribe https://github.com/notifications/unsubscribe-auth/APTQDOXGU3FXEWTOBNP6WS3R3E7JZANCNFSM4OXT2LXA.

wclodius2 commented 4 years ago

After checking my Ada textbook, I found that one thing I wrote about Ada is wrong so I am going to correct the proposal.

wclodius2 commented 4 years ago

Removed the comment implying Ada was the exception in having a specification part.

klausler commented 4 years ago

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

This would invalidate existing code, yes?

milancurcic commented 4 years ago

@klausler I'm pretty sure @wclodius2 meant "Restricting default arguments...". This proposal won't invalidate existing code. If it does, we will fix it.

jvdp1 commented 4 years ago

This would invalidate existing code, yes?

After having read the document, you should indeed read "Restricting default arguments...".

wclodius2 commented 4 years ago

A thinko. The proposal talks about restricting default arguments to arguments with the INTENT(IN), VALUE, or no intent attributes, which doesn’t invalidate existing code.

On Jul 12, 2020, at 12:04 PM, Peter Klausler notifications@github.com wrote:

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

This would invalidate existing code, yes?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/j3-fortran/fortran_proposals/pull/175#issuecomment-657255853, or unsubscribe https://github.com/notifications/unsubscribe-auth/APTQDOX2O63XOWBLYBUV523R3H3JZANCNFSM4OXT2LXA.

wclodius2 commented 4 years ago

Unfortunately no intent is not equivalent to intent(inout), though I wouldn’t object strongly if the revised proposal dropped allowing default assignment for no intent. INTENT(INOUT) means that the input value is always intended to be used and an output value is always expected. No INTENT could behave as an INTENT(IN), INTENT(OUT), or INTENT(INOUT), and its behavior could depend dynamically on the other arguments.

On Jul 12, 2020, at 12:40 PM, Jeremie Vandenplas notifications@github.com wrote:

@jvdp1 commented on this pull request.

Thank you for this revision. I added minor comments around "no intent" and intent(inout). I am not sure what the issues are.

In proposals/default_optional_arguments/revised_proposal.txt https://github.com/j3-fortran/fortran_proposals/pull/175#discussion_r453346448:

+ +1. Introduction + +This paper contains a proposal for Fortran 202y, to allow a programmer +to specify a default value for a subset of optional dummy +arguments. This would allow the programmer to then safely reference +such arguments in expressions regardless of whether the actual +argument is present or not. + + +2. Problem + +Fortran 2018 does not allow setting a default value for optional +arguments. A default value is the value that the dummy argument +would take if the corresponding actual argument is not present. If a +dummy argument of INTENT(IN) or VALUE, or no intent is declared as Is no intent equivalent to intent(inout)?

In proposals/default_optional_arguments/revised_proposal.txt https://github.com/j3-fortran/fortran_proposals/pull/175#discussion_r453347218:

+ +This differs from the INTENT(IN), VALUE, and no intent case: first, +because one assigns the default value with INTENT(OUT) when the actual +argument is present, not when it is absent; and second, because the +assignment of a default involves only one statement rather than the +three statements for the helper variable of INTENT(IN), VALUE, and no +intent. For INTENT(INOUT), one typically makes the argument optional +to avoid the computational expense of calculating the out result, but +having a default value makes it awkward to determine the presence of +an optional argument, so the primary purpose of having it be optional +is defeated. + +This proposal addresses the issue for INTENT(IN), VALUE, and no intent +arguments that checking for the presence of the optional dummy +argument and using a helper variable is cumbersome and error-prone. We +will not address default values for INTENT(OUT) OR INTENT(INOUT) I am not sure to understand why intent(inout) is not considered.If no argument is passed, then intent(inout) would behave as intent(in)?

In proposals/default_optional_arguments/revised_proposal.txt https://github.com/j3-fortran/fortran_proposals/pull/175#discussion_r453347347:

+greatest in scenarios where the optional argument is used in many +places in the procedure, and a helper variable is used for its value +instead. Reduction in needed source code would result in more readable +and more correct programs. + + +3. Prior art + +We are not aware of any Fortran compiler that has implemented default +arguments. However it is a very common feature of other languages. Of +interpreted languages widely used in the scientific community: +Python, IDL, R, and Matlab all have default arguments. Of compiled +languages C++ and Ada may be the best known with default arguments. Of +these languages, Ada may be the most pertinent as it has INTENT +arguments similar to Fortran's. Ada has only defined default arguments +useful for INTENT(IN), and has not defined it for INTENT(OUT) or I don't know Ada. What does it implement for "no intent"?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/j3-fortran/fortran_proposals/pull/175#pullrequestreview-446899013, or unsubscribe https://github.com/notifications/unsubscribe-auth/APTQDOVNQNPJVPHR7QL5F5DR3H7SVANCNFSM4OXT2LXA.

jvdp1 commented 4 years ago

Unfortunately no intent is not equivalent to intent(inout), though I wouldn’t object strongly if the revised proposal dropped allowing default assignment for no intent. INTENT(INOUT) means that the input value is always intended to be used and an output value is always expected. No INTENT could behave as an INTENT(IN), INTENT(OUT), or INTENT(INOUT), and its behavior could depend dynamically on the other arguments.

Thank you for the precisions. Therefore, because "no intent" could behave as an intent(out), wouldn't it make sense to not allowing default assignment for "no intent"? Otherwise, users could just drop "intent(out)" and add a default value for an argument actually behaving as intent(out)

wclodius2 commented 4 years ago

Like I said I have no strong feelings about no intent. The users can do a lot of things in almost any programming language that I would consider foolish. With no intent the user could also write the code in such a way that when he provides no argument so the default is used, the routine behaves like an INTENT(IN) and behaves like INTENT(INOUT) otherwise.. Whatever we decide we should discuss the implications for no intent, either requiring that an argument with the DEFAULT may not have the INTENT(INOUT) or INTENT(OUT) (implicitly allowing no intent), or require that arguments with the DEFAULT attribute must have one of the attributes INTENT(IN) or VALUE (implicitly disallowing no intent).

On Jul 12, 2020, at 2:07 PM, Jeremie Vandenplas notifications@github.com wrote:

Unfortunately no intent is not equivalent to intent(inout), though I wouldn’t object strongly if the revised proposal dropped allowing default assignment for no intent. INTENT(INOUT) means that the input value is always intended to be used and an output value is always expected. No INTENT could behave as an INTENT(IN), INTENT(OUT), or INTENT(INOUT), and its behavior could depend dynamically on the other arguments.

Thank you for the precisions. Therefore, because "no intent" could behabe as an intent(out), wouldn't it make sense to not allowing default assignment for "no intent"? Otherwise, users could just drop "intent(out)" and add a default value for an argument actually behaving as intent(out)

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

certik commented 3 years ago

I don't like specifying the default value in the argument list as in real function quadratic(x, a, b, c=0). I am ok with using default (and not mix this with optional).

One objection from the committee I believe is that the syntax integer, intent(in), default :: c = 0 implies the save attribute. So perhaps this syntax should be used instead: integer, intent(in), default(0) :: c.

milancurcic commented 3 years ago

One objection from the committee I believe is that the syntax integer, intent(in), default :: c = 0 implies the save attribute.

I don't understand this objection because dummy arguments can't have a save attribute.

I am also okay with not mixing default and optional. I slightly prefer the default :: c = 0 syntax, but default(0) :: c is fine too.

klausler commented 3 years ago

You need to decide whether the default value of a dummy argument (or just that fact that it has one) is meant to be a characteristic of the procedure or not. This matters in the implementation, because it determines whether an implementation has the freedom to implement the default value in the caller (as in C++) or in the called subprogram, or whether the language is forcing one or the other.

Why this matters: if the default value of a dummy argument is an expression involving other dummy arguments, host-associated variables, module or COMMON objects, &c., implementing the evaluation of the default value in the caller can be difficult or impossible. But if default values are expressions to be evaluated if need be in the called subprogram, then the value need not be part of the characteristics or interface, and the implementation of the calling side is no different from an OPTIONAL argument; and one could argue that an explicit interface need not distinguish between OPTIONAL and having a default value for purposes of procedure pointer assignment and other interface compatibility checking.

certik commented 3 years ago

Peter, when I discussed that at the last meeting (after the plenary), I think our idea was to implement the default value in the caller, which enables the compiler to compile the subroutine ahead of time without any if statements, and call it exactly the same way no matter if the user provides the default argument or not.

You have a good point about what if the default value is an expression involving other dummy arguments that it might be impossible. I don't know yet if it is impossible, and so a prior compiler implementation would be in order here. At least in gfortran it seems any of these expressions (such as a length of an array) is part of the function signature, so this would be also.

klausler commented 3 years ago

Peter, when I discussed that at the last meeting (after the plenary), I think our idea was to implement the default value in the caller, which enables the compiler to compile the subroutine ahead of time without any if statements, and call it exactly the same way no matter if the user provides the default argument or not.

You have a good point about what if the default value is an expression involving other dummy arguments that it might be impossible. I don't know yet if it is impossible, and so a prior compiler implementation would be in order here. At least in gfortran it seems any of these expressions (such as a length of an array) is part of the function signature, so this would be also.

subroutine host(defaultY)
  real, intent(in) :: defaultY
  call solver(f)
 contains
  real function f(x, y)
    real, intent(in) :: x, y
    default(defaultY) :: y
    ...
  end function
end subroutine

Seems like a compelling use case to me, but the default has to be implemented in the called subprogram to make it work. So there's reasons why defaults should be implemented in callees, and the only argument for implementing them in callers (it might save a predictable branch) is weak and also has other obvious solutions.

certik commented 3 years ago

I see. The nested subroutine f has access to the variables in the parent scope, such as defaultY, so this would work if the default is not part of the signature, using the current mechanism for nested subroutines. But if it is part of the signature of f, then one needs access to defaultY inside the function solver, which currently is not possible. Good point, thank you @klausler.

klausler commented 3 years ago

I see. The nested subroutine f has access to the variables in the parent scope, such as defaultY, so this would work if the default is not part of the signature, using the current mechanism for nested subroutines. But if it is part of the signature of f, then one needs access to defaultY inside the function solver, which currently is not possible. Good point, thank you @klausler.

Here's an idea: extend the VALUE attribute to accept an expression, and allow it to be applied to an OPTIONAL dummy argument as its default value. (You could also accept VALUE with an expression to specify a per-invocation initializer for a local variable, too, I suppose.)