From owner-sc22wg5+sc22wg5-dom8=www.open-std.org@open-std.org  Thu Sep 28 20:53:08 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 1ED3E358929; Thu, 28 Sep 2017 20:53:08 +0200 (CEST)
Delivered-To: sc22wg5@open-std.org
Received: from mail.jpl.nasa.gov (smtp.jpl.nasa.gov [128.149.139.105])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by www.open-std.org (Postfix) with ESMTP id 130E03585C0
	for <sc22wg5@open-std.org>; Thu, 28 Sep 2017 20:53:05 +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 v8SIr1QJ019853
	(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128 bits) verified NO)
	for <sc22wg5@open-std.org>; Thu, 28 Sep 2017 11:53:02 -0700
Subject: Re: (j3.2006) (SC22WG5.5977)   Generic programming examples
From: Van Snyder <Van.Snyder@jpl.nasa.gov>
Reply-To: Van.Snyder@jpl.nasa.gov
To: sc22wg5 <sc22wg5@open-std.org>
In-Reply-To: <75FA944E-F3CC-469F-9334-25F0E19F1A93@cray.com>
References: <20170927201113.6D137358742@www.open-std.org>
	 <CEB03336-C898-4C72-9BB9-C533DBDFC4C8@cray.com>
	 <20170928020816.B2E4D358742@www.open-std.org>
	 <20170928123430.2C442358929@www.open-std.org>
	 <75FA944E-F3CC-469F-9334-25F0E19F1A93@cray.com>
Content-Type: text/plain; charset="ISO-8859-1"
Organization: Yes
Date: Thu, 28 Sep 2017 11:53:01 -0700
Message-ID: <1506624781.32527.317.camel@math.jpl.nasa.gov>
Mime-Version: 1.0
X-Mailer: Evolution 2.32.3 (2.32.3-37.el6) 
Content-Transfer-Encoding: 7bit
X-Source-Sender: Van.Snyder@jpl.nasa.gov
X-AUTH: Authorized
Sender: owner-sc22wg5@open-std.org
Precedence: bulk

On Thu, 2017-09-28 at 16:18 +0000, Bill Long wrote:
> A type bound  procedure referenced though a polymorphic variable
> cannot itself be a template because the compiler does not know what
> procedure is being called at compile time.

Of course it can't be a template, but it can be an instance of a
template, as illustrated in my original example.  OTOH, if the type and
procedure are both in a parameterized module, it's even simpler and more
obvious there's no problem.

In my example

module Splines ( RK ) ! or maybe module ( RK ) Splines
  integer, public, kind :: RK ! Module parameter
  type, public :: Coeffs ! Doesn't have a type parameter
    real(rk), allocatable :: A(:), B(:), C(:), D(:)
  contains
    procedure Eval_
    generic :: Eval => Eval_
  end type Coeffs
  private :: Eval_
contains
  subroutine Eval_ ( C, X, Y ) ! Isn't a "template"
    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

I can extend the Splines module and its Coeffs type to include
coefficients to compute derivatives of the spline, and extend the Eval
generic binding to compute the value and derivative.

module Splines_Deriv ( RK )
  integer, public :: RK
  use, public :: Splines ( rk )
  type, public, extends(coeffs) :: Coeffs_Deriv
    real(rk), allocatable :: E(:), F(:), G(:), H(:)
  contains
    procedure Eval_Deriv
    generic :: Eval => Eval_Deriv
  end type Coeffs_Deriv
contains
  subroutine Eval_Deriv ....
end module Splines_Deriv

When I write

  use Splines_Deriv ( kind(1.0d0) )

both Splines_Deriv and Splines are instantiated, the latter an
"internal" module of Splines_Deriv.

You can access the Coeffs type from the Splines instance in the
Splines_Deriv instance because it's a public name in the instance of
Splines_Deriv:

  use Splines_Deriv ( kind(1.0d0) ), only: Coeffs_Deriv_D => Coeffs_Deriv, &
    & Coeffs_D => Coeffs

By extending the syntax of the use statement to allow naming the
instance of the parameterized module, and allowing to qualify the
<module-name> in the use statement to specify "internal" modules, it
would be possible to make explicit access to them:

  use MySplines_Deriv_D => Splines_Deriv ( kind(1.0d0) )
  use MySplines_Deriv_D%Splines, only: Coeffs_D => Coeffs

This avoids instantiating Splines again (unless you really want to).

All of this hangs together consistently because the type and its
procedure are parameterized by the same module parameter.

You can use a parameterized procedure with a parameterized type without
parameterizing the module, but the scheme has holes in it:

Module Splines
  integer, public, parameter :: DK = kind(0.0e0), SK = kind(0.0e0)
  type :: Coeffs(rk)
    integer, kind :: RK
    real(rk), allocatable :: A(:), B(:), C(:), D(:)
  contains
    procedure :: Eval_D, Eval_S
    generic :: Eval => Eval_D, Eval_S
  end type Coeffs
contains
  subroutine (RK)  Eval ( C, X, Y )
    integer :: RK
    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
  procedure :: Eval_D => Eval (DK)
  procedure :: Eval_S => Eval (SK)
end module Splines

In this case, somebody could still get into trouble:

use Splines, only: Coeffs, DK, Eval
integer, parameter :: QK = selected_real_kind ( 1 + precision(1.0_dk) )
procedure :: Eval_Q => Eval (QK) ! Instantiate parameterized subroutine
type (coeffs(qk)) :: Coeff_Q
call coeff_q%eval(...)

This doesn't work because Eval_Q isn't bound to Coeffs, and there's no
way other than by extending Coeffs to add the binding.

A parameterized module avoids this problem.  We should not do
parameterized procedures without doing parameterized modules.


