Skip to content

Initial draft of conditional expression intrinsic paper #213

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

Merged
merged 13 commits into from
Jun 27, 2021

Conversation

certik
Copy link
Member

@certik certik commented Jun 26, 2021

The paper explains the motivation.

The other two referenced papers are:

@klausler, @milancurcic, would you have time to please review this and help me polish it? I would like to submit this for Monday's vote also.

@certik
Copy link
Member Author

certik commented Jun 26, 2021

I believe this idea (not a specific proposal though) was discussed by the committee and the following feedback is summarized in:

Half the arguments are with issues that come up with extending merge, so we already avoid them by introducing a new intrinsic. The other half of the arguments we should address.

The first counter argument is harder chaining, but I think you just put the extra parenthesis at the end. Not too bad, it still seams more readable overall than alternatives.

The stronger counter argument is that this does not behave like a function, the ifthen is effectively a new syntax. At that point we might as well introduce new syntax. How to address this? The best argument I can come up is optional arguments, which can get passed through to another function with an optional argument and they are not evaluated ahead of time, as it would not work if the argument is not present. In a similar sense, the arguments of ifthen can be such "optional style" arguments that are not evaluated at the call site, but only (optionally) inside the function (similar to how present(x) works). So the concept is not completely new to Fortran. Is there a better way to address this argument?

@zjibben
Copy link
Member

zjibben commented Jun 27, 2021

One other not-a-function aspect is that a conditional expression can return an actual variable, not just the value. So it can be used in intent(out) contexts like allocate(x, stat=ifthen(logical, stat1, stat2)). I don't imagine there's a precedent for that kind of behavior for a function. Still, the point stands that there's a precedent for function-looking things not really behaving like functions.

But your paper looks good and should invite discussion.

Copy link
Member

@milancurcic milancurcic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, Ondrej! Besides my in-text comments, here are a few general comments and questions:

  • Can this function be simple? I think so.
  • In this approach, consequent and alternative must be type compatible. This is a restriction relative to the keyword (and other) forms, where you could do:
    res = if cond then 1 else 1.234
    
    or with a Python-like syntax:
    res = 1 if cond else 1.234
    
    Because of this restriction, I don't think ifthen could be used to invoke different specific procedures when passed as an argument to a generic procedure, which seems an attractive use case to me. But maybe I miss an important detail.

@certik
Copy link
Member Author

certik commented Jun 27, 2021

* In this approach, `consequent` and `alternative` must be type compatible. This is a restriction relative to the keyword (and other) forms, where you could do:
  ```
  res = if cond then 1 else 1.234
  ```

First of all, the keyword version would be:

res = if (cond) then (1) else (1.234) endif

and my understanding is that it would be exactly equivalent to:

res = ifthen(cond, 1, 1.234)

The restriction on consequent and alternative would be exactly the same. So either both integers or both reals (depending on the type of res, or perhaps somehow figured out from consequent and alternative, or perhaps it would not be allowed unless the types are exactly the same), and the default Fortran implicit casting rules apply.

@certik
Copy link
Member Author

certik commented Jun 27, 2021

So it can be used in intent(out) contexts like allocate(x, stat=ifthen(logical, stat1, stat2))

Isn't this semantically exactly the same as:

allocate(x, stat=if (logical) then (stat1) else (stat2) endif)

I would think both could return a variable. But I haven't thought of it like this. I would expect both if ... endif and ifthen to always return a value.

@milancurcic
Copy link
Member

Yes, actually my second comment and examples are completely irrelevant, the keyword form has the same restriction for types. It wasn't obvious to me that it would have to have it, but it does simplify things.

@certik
Copy link
Member Author

certik commented Jun 27, 2021

I pushed in answers to some common objections. @milancurcic, @zjibben let me know if you have any other feedback, or if I should upload as is.

Copy link
Member

@milancurcic milancurcic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found two small typos, otherwise I think it's in good shape. The longer chained example is not bad at all, I find it quite readable. Thanks for leading this proposal.

@certik
Copy link
Member Author

certik commented Jun 27, 2021

Thanks @milancurcic for the quick review. I think @zjibben implicitly approved it, so I am going to go ahead and upload it.

@certik
Copy link
Member Author

certik commented Jun 27, 2021

Ok there it is: https://j3-fortran.org/doc/year/21/21-165.txt

@certik certik merged commit c7aa0e1 into j3-fortran:master Jun 27, 2021
@certik certik deleted the cond branch June 27, 2021 05:16
@ashe2
Copy link

ashe2 commented Jun 28, 2021

What if you have this conforming program unit:

function f(cond, a, b)
  logical :: cond
  real :: f, a, b
  f = ifthen(cond, a, b)
end

Would this feature change the meaning of it? I.e. ifthen would change from an external to an intrinsic?

@klausler
Copy link

What if you have this conforming program unit:

function f(cond, a, b)
  logical :: cond
  real :: f, a, b
  f = ifthen(cond, a, b)
end

Would this feature change the meaning of it? I.e. ifthen would change from an external to an intrinsic?

Not if the program had a declaration of ifthen; a use, interface, external, &c would do. (But not just a declaration of its result type; if ifthen became an intrinsic, something like complex ifthen would then be completely ignored. Kind of a bug in the language, IMO.)

@ashe2
Copy link

ashe2 commented Jun 29, 2021

Would this feature change the meaning of it? I.e. ifthen would change from an external to an intrinsic?

Not if the program had a declaration of ifthen; a use, interface, external, &c would do.

As the example didn't have a declaration of ifthen, the meaning would change, right?

Is this a backward compatibility problem for any new intrinsic procedure?

@klausler
Copy link

Would this feature change the meaning of it? I.e. ifthen would change from an external to an intrinsic?

Not if the program had a declaration of ifthen; a use, interface, external, &c would do.

As the example didn't have a declaration of ifthen, the meaning would change, right?

Is this a backward compatibility problem for any new intrinsic procedure?

Yes, and yes. This is always a consideration when standard or extension intrinsic functions are added. If you use IMPLICIT NONE(EXTERNAL) , you're safe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants