6

I am trying to create heterogeneous arrays that contain variables of different types, for example, [ 1.0, 7, "hi" ]. I tried to include class(*) or type(*) in the array constructor (please see the end of the following code), but gfortran5.2 simply regards it as syntax error. Is there any way to make such an array with array constructor, or is it necessary to use a different approach (e.g., define a type that contains each element separately)?


More details:

The following code is an example why I want to create such an array. The checktype_multi routine receives multiple arguments with the optional keyword, but this approach is clearly limited because of the fixed number of arguments. To allow arbitrary number of arguments, I tried the checktype_array routine, but it seems not possible to pass an array with different types... A more practical case may be to make a subroutine for printing a variable number of arguments with various types.

module mymod
    implicit none
contains

    subroutine checktype ( x )
        class(*) :: x

        select type ( x )
            type is ( integer )      ; print *, "int    : ", x
            type is ( real )         ; print *, "real   : ", x
            type is ( character(*) ) ; print *, "string : ", x
        endselect
    end subroutine

    subroutine checktype_multi ( x1, x2, x3 )
        class(*), optional :: x1, x2, x3

        print *
        if ( present( x1 ) ) call checktype ( x1 )
        if ( present( x2 ) ) call checktype ( x2 )
        if ( present( x3 ) ) call checktype ( x3 )
    end subroutine

    subroutine checktype_array ( a )
        class(*) :: a(:)
        integer :: k

        print *
        do k = 1, size( a )
            call checktype ( a( k ) )
        enddo
    end subroutine

end module

program main
    use mymod

    call checktype_multi ( 1.0 )
    call checktype_multi ( 1.0, 7 )
    call checktype_multi ( 1.0, 7, "hi" )

    ! call checktype_array ( [ 1.0, 7, "hi" ] )  !! error (this is to be expected)

    !>>> Here is the problem.
    ! call checktype_array ( [ type(*)  :: 1.0, 7, "hi" ] )  !! this is also an error
    ! call checktype_array ( [ class(*) :: 1.0, 7, "hi" ] )  !! this too
end program
Community
  • 1
  • 1
roygvib
  • 7,218
  • 2
  • 19
  • 36

1 Answers1

6

The elements of an array may only differ from each other in value. They cannot differ in type, or any other attribute.

Instead, use a derived type wrapper around an unlimited polymorphic allocatable component. The dynamic type of the component is then considered part of the value of the object of the wrapper type.

TYPE :: wrapper
  CLASS(*), ALLOCATABLE :: item
END TYPE wrapper

CALL sub([wrapper(1), wrapper(2.0), wrapper('3')])

(An array constructor (or structure constructor) specifies a value. A value itself cannot be polymorphic, the type of the value is always just the type of the value. The syntax for optional leading type-spec in an array constructor reflects this, in that it is just a type-spec, not a declaration-type-spec.)

IanH
  • 21,026
  • 2
  • 37
  • 59
  • Hi @IanH, Thanks very much for you info. Because the `checktype_multi` routine was able to receive literals of different types (like 1.0 and 7) directly as actual arguments, I imagined that they may be converted internally (within a compiler) to some internal C objects that represent those data (for example, something like a `struct` consisting of a pointer to raw data plus some run-time time information). (cont.) – roygvib Nov 10 '15 at 17:22
  • So I wondered if there are any convenient ways to construct a Fortran array of hetero data directly, e.g., an array consisting of internal objects referred to by class(*) (as some newer Fortran feature). But this seems not the case according to your answer. Thanks very much :) – roygvib Nov 10 '15 at 17:32
  • And one more question: gfortran5.2 still gives error with your code ("Cannot convert integer to Class(*)" etc), but is this because gfortran5.2 is still behind the latest standard? Because I only have ifort14 (and cannot install newer versions in my environment), I wondered if the code compiles straight with newer compilers. (If more explicit codes are necessary I will make it a Question.) – roygvib Nov 10 '15 at 17:35
  • Another question (sorry for many...): Does `class(*) :: a(:)` represent a polymorphic array that can refer to a family of `type(T) :: a(:)` (with arbitrary T) rather than an array consisting of class(*) scalars? If so, I am afraid I am also making a big mistake with `class(*) :: a(:)` also.... (This may be similar to the fact that `type(T), pointer :: a(:)` represents a pointer to `type(T) :: a(...)` rather than an array of pointers to type(T) scalars.) – roygvib Nov 10 '15 at 18:14
  • 1
    gfortran is not yet a Fortran 2003 (or Fortran 2008) compiler. Current trunk does not appear to support definition of an unlimited polymorphic component via a structure constructor. I think the first sentence of my answer also answers the other question - all elements of an array must have the same [dynamic and declared] type. – IanH Nov 11 '15 at 05:52
  • OK, now I think I fully understand. Thanks very much! :) – roygvib Nov 11 '15 at 13:20