From owner-sc22wg5+sc22wg5-dom8=www.open-std.org@open-std.org  Thu Sep 28 04:08:16 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 867BC9DB171; Thu, 28 Sep 2017 04:08:16 +0200 (CEST)
Delivered-To: sc22wg5@open-std.org
Received: from ndjsvnpf103.ndc.nasa.gov (NDJSVNPF103.ndc.nasa.gov [198.117.1.153])
	(using TLSv1 with cipher AES128-SHA (128/128 bits))
	(No client certificate requested)
	by www.open-std.org (Postfix) with ESMTP id EB72A3586CF
	for <sc22wg5@open-std.org>; Thu, 28 Sep 2017 04:08:11 +0200 (CEST)
X-Comment: SPF check N/A for local connections - client-ip=198.117.0.47; helo=ndmsppt202.ndc.nasa.gov; envelope-from=thomas.l.clune@nasa.gov; receiver=sc22wg5@open-std.org 
DKIM-Filter: OpenDKIM Filter v2.11.0 ndjsvnpf103.ndc.nasa.gov 6FF2A4005D8E
Received: from ndmsppt202.ndc.nasa.gov (NDMSPPT202.ndc.nasa.gov [198.117.0.47])
	by ndjsvnpf103.ndc.nasa.gov (Postfix) with ESMTP id 6FF2A4005D8E;
	Wed, 27 Sep 2017 21:08:09 -0500 (CDT)
Received: from pps.filterd (ndmsppt202.ndc.nasa.gov [127.0.0.1])
	by ndmsppt202.ndc.nasa.gov (8.16.0.21/8.16.0.21) with SMTP id v8S24EUl123656;
	Wed, 27 Sep 2017 21:08:09 -0500
Authentication-Results: ndc.nasa.gov;
	spf=none smtp.mailfrom=thomas.l.clune@nasa.gov;
	dmarc=none
Received: from ndmscht108.ndc.nasa.gov (ndmscht108-pub.ndc.nasa.gov [198.117.0.208])
	by ndmsppt202.ndc.nasa.gov with ESMTP id 2d8kq7919t-1;
	Wed, 27 Sep 2017 21:08:09 -0500
Received: from NDMSMBX303.ndc.nasa.gov ([169.254.2.237]) by
 NDMSCHT108.ndc.nasa.gov ([198.117.0.178]) with mapi id 14.03.0319.002; Wed,
 27 Sep 2017 21:08:08 -0500
From: "Clune, Thomas L. (GSFC-6101)" <thomas.l.clune@nasa.gov>
To: fortran standards email list for J3 <j3@mailman.j3-fortran.org>
CC: Van Snyder <Van.Snyder@jpl.nasa.gov>, sc22wg5 <sc22wg5@open-std.org>
Subject: Re: (j3.2006) (SC22WG5.5973) Generic programming examples
Thread-Topic: (j3.2006) (SC22WG5.5973) Generic programming examples
Thread-Index: AQHTN8zMN7jpyGWOp0KI7F9+a/Qg5g==
Date: Thu, 28 Sep 2017 02:08:07 +0000
Message-ID: <55718F4F-5B5F-4416-A257-6B2D1E4DF8F0@nasa.gov>
References: <20170927201113.6D137358742@www.open-std.org>
 <CEB03336-C898-4C72-9BB9-C533DBDFC4C8@cray.com>
In-Reply-To: <CEB03336-C898-4C72-9BB9-C533DBDFC4C8@cray.com>
Accept-Language: en-US
Content-Language: en-US
X-MS-Has-Attach: 
X-MS-TNEF-Correlator: 
x-originating-ip: [71.120.6.15]
Content-Type: text/plain; charset="us-ascii"
Content-ID: <6FA6EF8AE2656C42AEBAE1BDDCC9065E@mail.nasa.gov>
Content-Transfer-Encoding: quoted-printable
MIME-Version: 1.0
X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2017-09-28_01:,,
 signatures=0
X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 spamscore=0 suspectscore=0
 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam
 adjust=0 reason=mlx scancount=1 engine=8.0.1-1707230000
 definitions=main-1709280030
X-Proofpoint-Envelope-Sender: thomas.l.clune@nasa.gov
Sender: owner-sc22wg5@open-std.org
Precedence: bulk

I disaggree.  It is crucial to have type-bound procedures.   This allows al=
l sorts of goodness when managing complex software.

Goodness #1:    I can create a mock subclass that allows me to test other c=
lients of this layer without dealing with the complexity of the class that =
I am mocking.

Goodness #2:   I can subclass with variant behavior without modifying other=
 code.

Using exceptions should not make us lose this other extremely important cap=
ability!

With the advent of mature F2003 support in vendors, I would guess that less=
 that 15% of my new procedures and subroutines are anything other than type=
-bound procedures.    The major exceptions are helper procedures _within_ t=
ype-bound procedures and the occasional quick-and-dirty procedure in a driv=
er.

> On Sep 27, 2017, at 7:16 PM, Bill Long <longb@cray.com> wrote:
>=20
> Or maybe just
>=20
> 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=3D*)) :: c
>     real(*), intent(in) :: x
>     real(*), intent(out) :: y
>    <computation part here>
>  end subroutine eval
> end module Splines
>=20
> For simple cases, generics are unnecessary if you have templates.  And th=
e complication of type-bound procedures seems unnecessary as well.  Simple,=
 clean code is almost always better.=20
>=20
>=20
> Cheers,
> Bill
>=20
>=20
>=20
>> On Sep 27, 2017, at 3:11 PM, Van Snyder <van.snyder@jpl.nasa.gov> wrote:
>>=20
>> Consider a module for spline interpolation:
>>=20
>> module Splines
>>   type :: Coeffs ( RK )
>>     integer, kind :: RK
>>     real, allocatable :: A(:), B(:), C(:), D(:)
>>   contains
>>     procedure :: Eval_D, Eval_S, ...
>>     generic :: Eval =3D> Eval_D, Eval_S
>>     ! And more procedures to compute A, B, C, D, etc.
>>   end type Coeffs
>>   integer, public, parameter :: DK =3D kind(0.0d0), SK =3D> kind(0.0e0)
>> contains
>>   subroutine Eval_D ( C, X, Y )
>>     integer, parameter :: RK =3D 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
>>=20
>>   subroutine Eval_S ( C, X, Y )
>>     integer, parameter :: RK =3D 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
>>=20
>> Now I need single, double and Q-precision splines:
>>=20
>> use Splines, only: Coeffs, DK, SK
>> integer, parameter :: QK =3D 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 )
>>=20
>> 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.
>>=20
>> 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.
>>=20
>> Let's do it using a parameterized procedure without a parameterized
>> module (the syntax extensions should be obvious):
>>=20
>> module Splines
>>   type :: Coeffs ( RK )
>>     integer, kind :: RK
>>     real, allocatable :: A(:), B(:), C(:), D(:)
>>   contains
>>     procedure :: Eval_D, Eval_S, ...
>>     generic :: Eval =3D> Eval_D, Eval_S
>>   end type Coeffs
>>   integer, public, parameter :: DK =3D kind(0.0d0), SK =3D> kind(0.0e0)
>>   procedure :: Eval_D =3D> Eval ( dk )
>>   procedure :: Eval_S =3D> 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
>>=20
>> Now I need single, double and Q-precision splines:
>>=20
>> 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:
>>=20
>> module Splines_Q
>>   use Splines, only: Coeffs, Eval
>>   type, extends(coeffs) :: Coeffs_Q
>>   contains
>>     procedure :: Eval_Q
>>     generic :: Eval =3D> Eval_Q
>>   end type Coeffs_Q
>>   integer, public, parameter :: QK =3D selected_real_kind ( 1 + precisio=
n(1.0d0) )
>>   procedure :: Eval_Q =3D> Eval ( qk )
>> end module Splines_Q
>>=20
>> 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 )
>>=20
>> Now let's do it using a parameterized module:
>>=20
>> 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
>>=20
>> Now I need single, double and Q-precision splines:
>>=20
>> use Splines ( kind(1.0d0) ), only: Coeffs_D =3D> Coeffs, DK =3D> RK
>> use Splines ( kind(1.0e0) ), only: Coeffs_S =3D> Coeffs, SK =3D> RK
>> use Splines ( selected_real_kind ( 1 + precision(1.0d0) ), only: Coeffs_=
Q =3D> Coeffs, &
>>   & QK =3D> RK
>>=20
>> 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 )
>>=20
>> 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.
>>=20
>> 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):
>>=20
>> integer, parameter :: DK =3D kind(0.0d0)
>> integer, parameter :: SK =3D kind(0.0e0)
>> integer, parameter :: QK =3D selected_real_kind ( 1 + precision(1.0d0) )
>>=20
>> use Splines ( dk ), only: Coeffs_D =3D> Coeffs
>> use Splines ( sk ), only: Coeffs_S =3D> Coeffs
>> use Splines ( qk ), only: Coeffs_Q =3D> Coeffs
>>=20
>> This was all laid out in much greater detail in 04-383r1, with many more
>> use case examples.
>>=20
>>=20
>> _______________________________________________
>> J3 mailing list
>> J3@mailman.j3-fortran.org
>> http://mailman.j3-fortran.org/mailman/listinfo/j3
>=20
> Bill Long                                                                =
       longb@cray.com
> Principal Engineer, Fortran Technical Support &   voice:  651-605-9024
> Bioinformatics Software Development                      fax:  651-605-91=
43
> Cray Inc./ 2131 Lindau Lane/  Suite 1000/  Bloomington, MN  55425
>=20
>=20
> _______________________________________________
> J3 mailing list
> J3@mailman.j3-fortran.org
> http://mailman.j3-fortran.org/mailman/listinfo/j3

