Skip to content
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

Allow an intent(out) argument to adopt the same kind as an input(in) argument #128

Open
certik opened this issue Jan 3, 2020 · 6 comments
Labels
Clause 15 Standard Clause 15: Procedures

Comments

@certik
Copy link
Member

certik commented Jan 3, 2020

Use case: when one wants to write a function that operates on all kinds, the only way currently is:

use kinds, only: sp, dp, qp
...
interface log10
    module subroutine log10_sp
    module subroutine log10_dp
    module subroutine log10_qp
end interface
...
real(sp) function log10_sp(x) result(r)
real(sp), intent(in) :: x
r = log(x) / log(10._sp)
end function

real(dp) function log10_dp(x) result(r)
real(dp), intent(in) :: x
r = log(x) / log(10._dp)
end function

real(qp) function log10_qp(x) result(r)
real(qp), intent(in) :: x
r = log(x) / log(10._qp)
end function

One can generate these in various ways (see fortran-lang/stdlib#35 where we discuss various approaches).

Instead, it would be nice if one could write the above as follows:

real(wp) function log10(x) result(r)
integer, parameter :: wp = kind(x)
real(wp), intent(in) :: x
r = log(x) / log(10._wp)
end function

Where one defines the local variable wp with the "working precision" of x. This would be a generic function (templated on the "kind"), that is instantiated when used to the actual kind of the input argument x at the call site.

This would work for subroutines also, e.g.:

subroutine log10(x, r)
integer, parameter :: wp = kind(x)
real(wp), intent(in) :: x
real(wp), intent(out) :: r
r = log(x) / log(10._wp)
end function

The way compilers would implement that is not by "templates" and "instantiation" but by simply immediately generating different versions of the log10 function for all the precisions that the compiler supports, typically three for reals (sp, dp and qp). So it should be about as fast to compile as the hand written first version above which does this explicitly. And once it is compiled, user code should be as fast to compile as today.

@klausler
Copy link

klausler commented Jan 3, 2020

You probably don't want to use both real(wp) and result(r) on the same function statement.

Let me suggest this revision:

function log10(x) result(r)
  real(kind=*), intent(in) :: x ! <- note the "assumed kind" type parameter
  integer, parameter :: wp = kind(x) ! no longer a forward reference to x
  real(kind=wp) :: r
  r = log(x) / log(10._wp)
end

@certik
Copy link
Member Author

certik commented Jan 3, 2020

@klausler that's better. Thanks!

@FortranFan
Copy link
Member

FortranFan commented Jan 4, 2020

@klausler wrote:

You probably don't want to use both real(wp) and result(r) on the same function statement.

Let me suggest this revision:

function log10(x) result(r)
  real(kind=*), intent(in) :: x ! <- note the "assumed kind" type parameter
  ..

Though I don't have ready references at the moment, indications are the Fortran standard committee has disfavored the "assumed kind" option, that they have insisted the kind type parameter to be either defaulted or be given by a constant expression. One can see evidence of this with parameterized derived type (PDT) facility starting Fortran 2003 that introduced assumed length parameter option with derived types but no assumed kind; and with assumed type ( TYPE(*) ) and assumed rank ( DIMENSION(..) ) options starting Fortran 2018. It's unclear whether such a position against assumed kind can change in the future.

Note the original post here is but one use case for proper GENERICS in Fortran. Toward generics, it appears the committee is open to the notion of certain UTILITIES e.g., TYPEOF/CLASSOF intrinsic inquiry functions that can employed in dummy argument declarations. In the same vein, I wonder if might be feasible to consider another utility, say ALL_OF, that can be allowed in constant expressions.

Considering the standard states in the context of standard intrinsic modules, "The processor shall provide the named constants, derived types, and procedures described in 16.10.2" and among the constants listed include the KINDs of intrinsinc types such as REAL_KINDS, INTEGER_KINDS, CHARACTER_KINDS, etc., a utility such as ALL_OF can make feasible the following which might make it easier for processors to do the needful, meaning put together all the necessary wiring toward the generic interface needed by a coder, as illustrated in the original post.

function log10(x) result(r)
   use, intrinsic :: iso_fortran_env, only : REAL_KINDS
   real(kind=ALL_OF(REAL_KINDS)), intent(in) :: x 
   integer, parameter :: wp = kind(x) ! no longer a forward reference to x
   real(kind=wp) :: r
   r = log(x) / log(10._wp)
end

@wclodius2
Copy link
Contributor

The TYPE_OF facility plans for 202X would simplify this usage.

@FortranFan
Copy link
Member

FortranFan commented Jul 1, 2020

@wclodius2 wrote June 30, 2020 3;40 PM EDT:

The TYPE_OF facility plans for 202X would simplify this usage.

No, it won't - see my earlier reply.

@certik
Copy link
Member Author

certik commented Jun 11, 2023

A similar proposal to specify the kind as an argument: #91.

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

No branches or pull requests

4 participants