From owner-sc22wg5+sc22wg5-dom8=www.open-std.org@open-std.org  Thu Sep 28 01:20:30 2017
Return-Path: <owner-sc22wg5+sc22wg5-dom8=www.open-std.org@open-std.org>
X-Original-To: sc22wg5-dom8
Delivered-To: sc22wg5-dom8@www.open-std.org
Received: by www.open-std.org (Postfix, from userid 521)
	id 351099DB171; Thu, 28 Sep 2017 01:20:30 +0200 (CEST)
Delivered-To: sc22wg5@open-std.org
Received: from mail.jpl.nasa.gov (sentrion2.jpl.nasa.gov [128.149.139.106])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by www.open-std.org (Postfix) with ESMTP id 4AF29358708
	for <sc22wg5@open-std.org>; Thu, 28 Sep 2017 01:20:25 +0200 (CEST)
Received: from [137.79.7.57] (math.jpl.nasa.gov [137.79.7.57])
	by smtp.jpl.nasa.gov (Sentrion-MTA-4.3.1/Sentrion-MTA-4.3.1) with ESMTP id v8RNKLr9028570
	(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128 bits) verified NO);
	Wed, 27 Sep 2017 16:20:23 -0700
Subject: Re: (j3.2006) (SC22WG5.5974)  Generic programming examples
From: Van Snyder <Van.Snyder@jpl.nasa.gov>
Reply-To: Van.Snyder@jpl.nasa.gov
To: fortran standards email list for J3 <j3@mailman.j3-fortran.org>
Cc: sc22wg5 <sc22wg5@open-std.org>
In-Reply-To: <20170927231633.7FD04358742@www.open-std.org>
References: <20170927201113.6D137358742@www.open-std.org>
	 <20170927231633.7FD04358742@www.open-std.org>
Content-Type: multipart/alternative; boundary="=-6C7sRJUdcX2fBFoBEWIC"
Organization: Yes
Date: Wed, 27 Sep 2017 16:20:21 -0700
Message-ID: <1506554421.32527.265.camel@math.jpl.nasa.gov>
Mime-Version: 1.0
X-Mailer: Evolution 2.32.3 (2.32.3-37.el6) 
X-Source-Sender: Van.Snyder@jpl.nasa.gov
X-AUTH: Authorized
Sender: owner-sc22wg5@open-std.org
Precedence: bulk


--=-6C7sRJUdcX2fBFoBEWIC
Content-Type: text/plain; charset="ISO-8859-1"
Content-Transfer-Encoding: 7bit

On Wed, 2017-09-27 at 23:16 +0000, Bill Long wrote:

> Or maybe just
> 
> module Splines
>   type :: Coefs (rk)
>      integer,kind :: rk
>      real,allocatable :: a(:), b(:), c(:), d(:)
>   end type Coefs
> contains
>   template subroutine eval (c, x, y)
>      type (coefs(rk=*)) :: c
>      real(*), intent(in) :: x
>      real(*), intent(out) :: y
>     <computation part here>
>   end subroutine eval
> end module Splines
> 
> For simple cases, generics are unnecessary if you have templates.  And the complication of type-bound procedures seems unnecessary as well.  Simple, clean code is almost always better. 



Go ahead and submit the proposal to eliminate type-bound procedures.  It
will be interesting to see how far that goes.

If we eliminate the problem, a solution isn't necessary.


> Cheers,
> Bill
> 
> 
> 
> > On Sep 27, 2017, at 3:11 PM, Van Snyder <van.snyder@jpl.nasa.gov> wrote:
> > 
> > Consider a module for spline interpolation:
> > 
> >  module Splines
> >    type :: Coeffs ( RK )
> >      integer, kind :: RK
> >      real, allocatable :: A(:), B(:), C(:), D(:)
> >    contains
> >      procedure :: Eval_D, Eval_S, ...
> >      generic :: Eval => Eval_D, Eval_S
> >      ! And more procedures to compute A, B, C, D, etc.
> >    end type Coeffs
> >    integer, public, parameter :: DK = kind(0.0d0), SK => kind(0.0e0)
> >  contains
> >    subroutine Eval_D ( C, X, Y )
> >      integer, parameter :: RK = dk
> >      class(coeffs(rk)), intent(in) :: C
> >      real(rk), intent(in) :: X
> >      real(rk), intent(out) :: Y
> >      include "Eval_Body.f9h"
> >    end subroutine Eval_D
> > 
> >    subroutine Eval_S ( C, X, Y )
> >      integer, parameter :: RK = sk
> >      class(coeffs(rk)), intent(in) :: C
> >      real(rk), intent(in) :: X
> >      real(rk), intent(out) :: Y
> >      include "Eval_Body.f9h"
> >    end subroutine Eval_S
> >    ....
> >  end module Splines
> > 
> > Now I need single, double and Q-precision splines:
> > 
> >  use Splines, only: Coeffs, DK, SK
> >  integer, parameter :: QK = selected_real_kind ( 1 + precision(1.0d0) )
> >  type(coeffs(dk)) :: C_D
> >  type(coeffs(sk)) :: C_S
> >  type(coeffs(qk)) :: C_Q
> >  real(dk) :: Y_d
> >  real(sk) :: Y_S
> >  real(qk) :: Y_q
> >  call c_d%eval ( 1.5_dk, y_d )
> >  call c_s%eval ( 1.5_sk, y_s )
> >  call c_q%eval ( 1.5_qk, y_q )
> > 
> > Notice that Splines doesn't define a Q-precision Eval_* subroutine, and
> > Coeffs doesn't provide a generic binding for one.  So the code won't
> > even compile.  Generic resolution fails because there is no Q-precision
> > generic to match c_q%eval.  This is a problem if all you have for your
> > spline library is .o and .mod files, and the company that provided it no
> > longer exists to give (or sell) you source to upgrade to your
> > requirements.
> > 
> > This is what Richard Maine warned about twenty years ago -- when Ada
> > generic packages had already been in use for fourteen years, and had
> > been part of the Ada requirements since before FORTRAN 77.
> > 
> > Let's do it using a parameterized procedure without a parameterized
> > module (the syntax extensions should be obvious):
> > 
> >  module Splines
> >    type :: Coeffs ( RK )
> >      integer, kind :: RK
> >      real, allocatable :: A(:), B(:), C(:), D(:)
> >    contains
> >      procedure :: Eval_D, Eval_S, ...
> >      generic :: Eval => Eval_D, Eval_S
> >    end type Coeffs
> >    integer, public, parameter :: DK = kind(0.0d0), SK => kind(0.0e0)
> >    procedure :: Eval_D => Eval ( dk )
> >    procedure :: Eval_S => Eval ( sk )
> >  contains
> >    subroutine (rk) Eval ( C, X, Y )
> >      integer :: RK
> >      class(coeffs(rk)), intent(in) :: C
> >      real(rk), intent(in) :: X
> >      real(rk), intent(out) :: Y
> >      ... (don't need Include "Eval_Body.f9h")
> >    end subroutine Eval
> >  end module Splines
> > 
> > Now I need single, double and Q-precision splines:
> > 
> > Assume I got only .o and .mod files from a vendor, so I don't have
> > source to upgrade.  So first, I need to extend Coeffs and define a
> > Q-precision evaluator:
> > 
> >  module Splines_Q
> >    use Splines, only: Coeffs, Eval
> >    type, extends(coeffs) :: Coeffs_Q
> >    contains
> >      procedure :: Eval_Q
> >      generic :: Eval => Eval_Q
> >    end type Coeffs_Q
> >    integer, public, parameter :: QK = selected_real_kind ( 1 + precision(1.0d0) )
> >    procedure :: Eval_Q => Eval ( qk )
> >  end module Splines_Q
> > 
> >  use Splines_Q, only: Coeffs_Q, DK, SK, QK
> >  type(coeffs_q(dk)) :: C_D
> >  type(coeffs_q(sk)) :: C_S
> >  type(coeffs_q(qk)) :: C_Q
> >  real(dk) :: Y_d
> >  real(sk) :: Y_S
> >  real(qk) :: Y_q
> >  call c_d%eval ( 1.5_dk, y_d )
> >  call c_s%eval ( 1.5_sk, y_s )
> >  call c_q%eval ( 1.5_qk, y_q )
> > 
> > Now let's do it using a parameterized module:
> > 
> >  module Splines ( RK )
> >    integer, public, kind :: RK ! Module parameter
> >    type :: Coeffs ! Doesn't have a type parameter
> >      real(rk), allocatable :: A(:), B(:), C(:), D(:)
> >    contains
> >      procedure Eval
> >    end type Coeffs
> >  contains
> >    subroutine Eval ( C, X, Y )
> >      class(coeffs), intent(in) :: C
> >      real(rk), intent(in) :: X
> >      real(rk), intent(out) :: Y
> >      ... (don't need Include "Eval_Body.f9h")
> >    end subroutine Eval
> >  end module Splines
> > 
> > Now I need single, double and Q-precision splines:
> > 
> >  use Splines ( kind(1.0d0) ), only: Coeffs_D => Coeffs, DK => RK
> >  use Splines ( kind(1.0e0) ), only: Coeffs_S => Coeffs, SK => RK
> >  use Splines ( selected_real_kind ( 1 + precision(1.0d0) ), only: Coeffs_Q => Coeffs, &
> >    & QK => RK
> > 
> >  type(coeffs_d) :: C_D
> >  type(coeffs_s) :: C_S
> >  type(coeffs_q) :: C_Q
> >  real(dk) :: Y_d
> >  real(sk) :: Y_s
> >  real(qk) :: Y_q
> >  call c_d%eval ( 1.5_dk, y_d )
> >  call c_s%eval ( 1.5_rk, y_s )
> >  call c_q%eval ( 1.5_qk, y_q )
> > 
> > This works, even if you don't have source code for the module.  It's
> > easy to construct a type and consistent related type-bound procedures.
> > You can't do that nearly so easily using parameterized procedures
> > without parameterized modules.  If you have a parameterized EVAL
> > procedure but you don't have the source for the Splines module, you need
> > to extend the type to add a binding for the Q-precision Eval subroutine.
> > It's not impossible, but it's ugly and requires more labor expense for
> > development and maintenance.
> > 
> > To make things a little bit smoother, we should allow declarations
> > before USE statements, so long as they depend only upon things declared
> > earlier (an already-ubiquitous requirement in the Fortran standard):
> > 
> >  integer, parameter :: DK = kind(0.0d0)
> >  integer, parameter :: SK = kind(0.0e0)
> >  integer, parameter :: QK = selected_real_kind ( 1 + precision(1.0d0) )
> > 
> >  use Splines ( dk ), only: Coeffs_D => Coeffs
> >  use Splines ( sk ), only: Coeffs_S => Coeffs
> >  use Splines ( qk ), only: Coeffs_Q => Coeffs
> > 
> > This was all laid out in much greater detail in 04-383r1, with many more
> > use case examples.
> > 
> > 
> > _______________________________________________
> > J3 mailing list
> > J3@mailman.j3-fortran.org
> > http://mailman.j3-fortran.org/mailman/listinfo/j3
> 
> Bill Long                                                                       longb@cray.com
> Principal Engineer, Fortran Technical Support &   voice:  651-605-9024
> Bioinformatics Software Development                      fax:  651-605-9143
> Cray Inc./ 2131 Lindau Lane/  Suite 1000/  Bloomington, MN  55425
> 
> 
> _______________________________________________
> J3 mailing list
> J3@mailman.j3-fortran.org
> http://mailman.j3-fortran.org/mailman/listinfo/j3



--=-6C7sRJUdcX2fBFoBEWIC
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: 7bit

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 TRANSITIONAL//EN">
<HTML>
<HEAD>
  <META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8">
  <META NAME="GENERATOR" CONTENT="GtkHTML/3.32.2">
</HEAD>
<BODY>
On Wed, 2017-09-27 at 23:16 +0000, Bill Long wrote:
<BLOCKQUOTE TYPE=CITE>
<PRE>
Or maybe just

module Splines
  type :: Coefs (rk)
     integer,kind :: rk
     real,allocatable :: a(:), b(:), c(:), d(:)
  end type Coefs
contains
  template subroutine eval (c, x, y)
     type (coefs(rk=*)) :: c
     real(*), intent(in) :: x
     real(*), intent(out) :: y
    &lt;computation part here&gt;
  end subroutine eval
end module Splines

For simple cases, generics are unnecessary if you have templates.  And the complication of type-bound procedures seems unnecessary as well.  Simple, clean code is almost always better. 
</PRE>
</BLOCKQUOTE>
<PRE>

</PRE>
Go ahead and submit the proposal to eliminate type-bound procedures.&nbsp; It will be interesting to see how far that goes.<BR>
<BR>
If we eliminate the problem, a solution isn't necessary.<BR>
<BR>
<BLOCKQUOTE TYPE=CITE>
<PRE>
Cheers,
Bill



&gt; On Sep 27, 2017, at 3:11 PM, Van Snyder &lt;<A HREF="mailto:van.snyder@jpl.nasa.gov">van.snyder@jpl.nasa.gov</A>&gt; wrote:
&gt; 
&gt; Consider a module for spline interpolation:
&gt; 
&gt;  module Splines
&gt;    type :: Coeffs ( RK )
&gt;      integer, kind :: RK
&gt;      real, allocatable :: A(:), B(:), C(:), D(:)
&gt;    contains
&gt;      procedure :: Eval_D, Eval_S, ...
&gt;      generic :: Eval =&gt; Eval_D, Eval_S
&gt;      ! And more procedures to compute A, B, C, D, etc.
&gt;    end type Coeffs
&gt;    integer, public, parameter :: DK = kind(0.0d0), SK =&gt; kind(0.0e0)
&gt;  contains
&gt;    subroutine Eval_D ( C, X, Y )
&gt;      integer, parameter :: RK = dk
&gt;      class(coeffs(rk)), intent(in) :: C
&gt;      real(rk), intent(in) :: X
&gt;      real(rk), intent(out) :: Y
&gt;      include &quot;Eval_Body.f9h&quot;
&gt;    end subroutine Eval_D
&gt; 
&gt;    subroutine Eval_S ( C, X, Y )
&gt;      integer, parameter :: RK = sk
&gt;      class(coeffs(rk)), intent(in) :: C
&gt;      real(rk), intent(in) :: X
&gt;      real(rk), intent(out) :: Y
&gt;      include &quot;Eval_Body.f9h&quot;
&gt;    end subroutine Eval_S
&gt;    ....
&gt;  end module Splines
&gt; 
&gt; Now I need single, double and Q-precision splines:
&gt; 
&gt;  use Splines, only: Coeffs, DK, SK
&gt;  integer, parameter :: QK = selected_real_kind ( 1 + precision(1.0d0) )
&gt;  type(coeffs(dk)) :: C_D
&gt;  type(coeffs(sk)) :: C_S
&gt;  type(coeffs(qk)) :: C_Q
&gt;  real(dk) :: Y_d
&gt;  real(sk) :: Y_S
&gt;  real(qk) :: Y_q
&gt;  call c_d%eval ( 1.5_dk, y_d )
&gt;  call c_s%eval ( 1.5_sk, y_s )
&gt;  call c_q%eval ( 1.5_qk, y_q )
&gt; 
&gt; Notice that Splines doesn't define a Q-precision Eval_* subroutine, and
&gt; Coeffs doesn't provide a generic binding for one.  So the code won't
&gt; even compile.  Generic resolution fails because there is no Q-precision
&gt; generic to match c_q%eval.  This is a problem if all you have for your
&gt; spline library is .o and .mod files, and the company that provided it no
&gt; longer exists to give (or sell) you source to upgrade to your
&gt; requirements.
&gt; 
&gt; This is what Richard Maine warned about twenty years ago -- when Ada
&gt; generic packages had already been in use for fourteen years, and had
&gt; been part of the Ada requirements since before FORTRAN 77.
&gt; 
&gt; Let's do it using a parameterized procedure without a parameterized
&gt; module (the syntax extensions should be obvious):
&gt; 
&gt;  module Splines
&gt;    type :: Coeffs ( RK )
&gt;      integer, kind :: RK
&gt;      real, allocatable :: A(:), B(:), C(:), D(:)
&gt;    contains
&gt;      procedure :: Eval_D, Eval_S, ...
&gt;      generic :: Eval =&gt; Eval_D, Eval_S
&gt;    end type Coeffs
&gt;    integer, public, parameter :: DK = kind(0.0d0), SK =&gt; kind(0.0e0)
&gt;    procedure :: Eval_D =&gt; Eval ( dk )
&gt;    procedure :: Eval_S =&gt; Eval ( sk )
&gt;  contains
&gt;    subroutine (rk) Eval ( C, X, Y )
&gt;      integer :: RK
&gt;      class(coeffs(rk)), intent(in) :: C
&gt;      real(rk), intent(in) :: X
&gt;      real(rk), intent(out) :: Y
&gt;      ... (don't need Include &quot;Eval_Body.f9h&quot;)
&gt;    end subroutine Eval
&gt;  end module Splines
&gt; 
&gt; Now I need single, double and Q-precision splines:
&gt; 
&gt; Assume I got only .o and .mod files from a vendor, so I don't have
&gt; source to upgrade.  So first, I need to extend Coeffs and define a
&gt; Q-precision evaluator:
&gt; 
&gt;  module Splines_Q
&gt;    use Splines, only: Coeffs, Eval
&gt;    type, extends(coeffs) :: Coeffs_Q
&gt;    contains
&gt;      procedure :: Eval_Q
&gt;      generic :: Eval =&gt; Eval_Q
&gt;    end type Coeffs_Q
&gt;    integer, public, parameter :: QK = selected_real_kind ( 1 + precision(1.0d0) )
&gt;    procedure :: Eval_Q =&gt; Eval ( qk )
&gt;  end module Splines_Q
&gt; 
&gt;  use Splines_Q, only: Coeffs_Q, DK, SK, QK
&gt;  type(coeffs_q(dk)) :: C_D
&gt;  type(coeffs_q(sk)) :: C_S
&gt;  type(coeffs_q(qk)) :: C_Q
&gt;  real(dk) :: Y_d
&gt;  real(sk) :: Y_S
&gt;  real(qk) :: Y_q
&gt;  call c_d%eval ( 1.5_dk, y_d )
&gt;  call c_s%eval ( 1.5_sk, y_s )
&gt;  call c_q%eval ( 1.5_qk, y_q )
&gt; 
&gt; Now let's do it using a parameterized module:
&gt; 
&gt;  module Splines ( RK )
&gt;    integer, public, kind :: RK ! Module parameter
&gt;    type :: Coeffs ! Doesn't have a type parameter
&gt;      real(rk), allocatable :: A(:), B(:), C(:), D(:)
&gt;    contains
&gt;      procedure Eval
&gt;    end type Coeffs
&gt;  contains
&gt;    subroutine Eval ( C, X, Y )
&gt;      class(coeffs), intent(in) :: C
&gt;      real(rk), intent(in) :: X
&gt;      real(rk), intent(out) :: Y
&gt;      ... (don't need Include &quot;Eval_Body.f9h&quot;)
&gt;    end subroutine Eval
&gt;  end module Splines
&gt; 
&gt; Now I need single, double and Q-precision splines:
&gt; 
&gt;  use Splines ( kind(1.0d0) ), only: Coeffs_D =&gt; Coeffs, DK =&gt; RK
&gt;  use Splines ( kind(1.0e0) ), only: Coeffs_S =&gt; Coeffs, SK =&gt; RK
&gt;  use Splines ( selected_real_kind ( 1 + precision(1.0d0) ), only: Coeffs_Q =&gt; Coeffs, &amp;
&gt;    &amp; QK =&gt; RK
&gt; 
&gt;  type(coeffs_d) :: C_D
&gt;  type(coeffs_s) :: C_S
&gt;  type(coeffs_q) :: C_Q
&gt;  real(dk) :: Y_d
&gt;  real(sk) :: Y_s
&gt;  real(qk) :: Y_q
&gt;  call c_d%eval ( 1.5_dk, y_d )
&gt;  call c_s%eval ( 1.5_rk, y_s )
&gt;  call c_q%eval ( 1.5_qk, y_q )
&gt; 
&gt; This works, even if you don't have source code for the module.  It's
&gt; easy to construct a type and consistent related type-bound procedures.
&gt; You can't do that nearly so easily using parameterized procedures
&gt; without parameterized modules.  If you have a parameterized EVAL
&gt; procedure but you don't have the source for the Splines module, you need
&gt; to extend the type to add a binding for the Q-precision Eval subroutine.
&gt; It's not impossible, but it's ugly and requires more labor expense for
&gt; development and maintenance.
&gt; 
&gt; To make things a little bit smoother, we should allow declarations
&gt; before USE statements, so long as they depend only upon things declared
&gt; earlier (an already-ubiquitous requirement in the Fortran standard):
&gt; 
&gt;  integer, parameter :: DK = kind(0.0d0)
&gt;  integer, parameter :: SK = kind(0.0e0)
&gt;  integer, parameter :: QK = selected_real_kind ( 1 + precision(1.0d0) )
&gt; 
&gt;  use Splines ( dk ), only: Coeffs_D =&gt; Coeffs
&gt;  use Splines ( sk ), only: Coeffs_S =&gt; Coeffs
&gt;  use Splines ( qk ), only: Coeffs_Q =&gt; Coeffs
&gt; 
&gt; This was all laid out in much greater detail in 04-383r1, with many more
&gt; use case examples.
&gt; 
&gt; 
&gt; _______________________________________________
&gt; J3 mailing list
&gt; <A HREF="mailto:J3@mailman.j3-fortran.org">J3@mailman.j3-fortran.org</A>
&gt; <A HREF="http://mailman.j3-fortran.org/mailman/listinfo/j3">http://mailman.j3-fortran.org/mailman/listinfo/j3</A>

Bill Long                                                                       <A HREF="mailto:longb@cray.com">longb@cray.com</A>
Principal Engineer, Fortran Technical Support &amp;   voice:  651-605-9024
Bioinformatics Software Development                      fax:  651-605-9143
Cray Inc./ 2131 Lindau Lane/  Suite 1000/  Bloomington, MN  55425


_______________________________________________
J3 mailing list
<A HREF="mailto:J3@mailman.j3-fortran.org">J3@mailman.j3-fortran.org</A>
<A HREF="http://mailman.j3-fortran.org/mailman/listinfo/j3">http://mailman.j3-fortran.org/mailman/listinfo/j3</A>
</PRE>
</BLOCKQUOTE>
<BR>
</BODY>
</HTML>

--=-6C7sRJUdcX2fBFoBEWIC--

