(j3.2006) How to assign to the declared-type part of a polymorphic allocatable array?

Clune, Thomas L. GSFC-6101 thomas.l.clune
Thu Sep 22 17:07:41 EDT 2016


The second solution you suggested  is much better in my opinion.    It allows user extensions without the need to modify the SELECT CASE statement, which is a guiding principle (open-closed) for OO design.

I also think a ?setter? method would accomplish what you want:

call geo%set_h_t(z%ZOT_to_geo())

Here set_h_t() is a type-bound procedure in the base class that has the h_t component.

A working simple example of this:

module base_mod
   type base
      real :: x
   contains
      procedure :: set
   end type base

contains

   elemental subroutine set(this, x)
      class (base), intent(inout) :: this
      real, intent(in) :: x

      this%x = x
   end subroutine set
end module base_mod

program main
   use base_mod
   implicit none

   class (base), allocatable :: list(:)

   allocate(base::list(4))

   call list%set([1.,2.,3.,4.])

   print*,list(1)%x
   print*,list(4)%x
end program main
   




> On Sep 22, 2016, at 4:50 PM, Van Snyder <Van.Snyder at jpl.nasa.gov> wrote:
> 
> Here's a nearly-as-ugly solution:
> 
> type :: H_t_0
>  type(lon_t) :: Lon
>  type(lat_t) :: Lat
> end type H_t_0
> 
> type, extends(h_t_0) :: H_t
> end type H_t
> 
> geo%h_t_0 = z%ZOT_to_geo()
> 
> Ugh.
> 
> On Thu, 2016-09-22 at 13:46 -0700, Van Snyder wrote:
>> Here's an ugly solution, that gets uglier and uglier as more extensions
>> of a type are created:
>> 
>> On Wed, 2016-09-21 at 19:57 -0700, Van Snyder wrote:
>>> Is there a way to assign to the declared-type part of a polymorphic
>>> allocatable array, other than one component at a time?
>>> 
>>> I have a type H_t (for horizontal geolocation) that contains latitude
>>> and longitude.  It's agnostic whether the latitude is geocentric or
>>> geodetic.  It has extensions H_Geoc (for geocentric latitude) and H_Geod
>>> (for geodetic latitude), H_V_t (including a height component V, agnostic
>>> whether geocentric or geodetic), H_V_Geoc (geocentric latitude and
>>> height), H_V_Geod (geodetic latitude and height), and others.
>>> 
>>> I have an object
>>> 
>>>  class(h_t), allocatable :: Geo(:)
>>> 
>>> which I allocate
>>> 
>>>  if ( geodetic ) then
>>>    allocate ( h_v_geod :: geo(n) )
>>>  else
>>>    allocate ( h_v_geoc :: geo(n) )
>>>  end if
>> 
>> select type ( geo )
>> class is ( h_geoc ) ! h_v_geoc is an extension of h_geoc
>>  geo%h_t = z%ZOT_to_geo()
>> class is ( h_geod ) ! h_v_geod is an extension of h_geod
>>  geo%h_t = z%ZOT_to_geo()
>> end select
>> 
>> I can't use a class default block because therein the declared type of
>> geo would be h_t, and it wouldn't have a nonpolymorphic h_t component to
>> which I can assign.
>> 
>>> I then want to fill the horizontal geolocations by applying an elemental
>>> type-bound function to an array of a type ZOT_t, from which latitudes
>>> and longitudes are computed.  The type ZOT_t represents a uniform
>>> triangular grid on a (-1:1 X -1:1) square, which is then projected by a
>>> zenitial orthogonal transformation onto a sphere.  The grid is developed
>>> to a specified refinement, without regard to whether latitudes computed
>>> from it will be ultimately interpreted as geocentric or geodetic.
>>> Therefore, the result of the type-bound function ZOT_to_Geo is
>>> type(H_t), not class(H_t).  So after allocating Geo, I'd like to assign
>>> to its horizontal geolocation components using
>>> 
>>>  geo%h_t = z%ZOT_to_geo()
>>> 
>>> (size(z) == n) but we've only provided for a parent component, not a
>>> "self" component, so geo%h_t doesn't exist.  I can't use
>>> 
>>>  geo = z%ZOT_to_geo()
>>> 
>>> for two reasons.  First, geo is polymorphic.  Second, it has a "v"
>>> component, that I'm not yet ready to fill.
>>> 
>>> Is there something simpler than this:
>>> 
>>>  block
>>>    type(h_t) :: T
>>>    integer :: I
>>>    do i = 1, n
>>>      t = z(i)%ZOT_to_geo()
>>>      geo(i)%lat = t%lat
>>>      geo(i)%lon = g%lon
>>>    end do
>>>  end block
>>> 
>>> Ignoring for a while the "v" component of h_v_geod, I tried
>>> 
>>>  allocate ( geo, source=h_geod(h_t=z%zot_to_geo()) )
>>> 
>>> but that doesn't work because structure constructors aren't elemental
>>> (how could they be?).  Maybe I could overload h_geod with an elemental
>>> function; I haven't tried that yet.
>>> 
>>> I tried
>>> 
>>>  allocate ( h_geod :: geo, source = z%zot_to_geo() )
>>> 
>>> but that doesn't work because it has both a type spec and a source.
>>> 
>>> I did finally make this work, but it seems like a needlessly wordy
>>> kludge:
>>> 
>>>  allocate ( geo, source = [ ( h_v_geod(h_t=z(i)%zot_to_geo(),v=0), i = 1, n ) ] )
>>> 
>>> Isn't there something simpler?
>>> 
>>> [BTW, it doesn't work with ifort 15.0.2.164.  It complains about a
>>> missing field [LAT] not being initialized.  Maybe it's been repaired
>>> already.  I have not yet been able to convince our SA to install the
>>> latest Intel release.]
>>> 
>>> 
>>> _______________________________________________
>>> J3 mailing list
>>> J3 at mailman.j3-fortran.org
>>> http://mailman.j3-fortran.org/mailman/listinfo/j3
>> 
> 
> 
> _______________________________________________
> J3 mailing list
> J3 at mailman.j3-fortran.org
> http://mailman.j3-fortran.org/mailman/listinfo/j3




More information about the J3 mailing list