Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28457 Discussions

Is there a way to pass a class(*),allocatable dummy argument to another subroutine via select type?

Roadelse
Novice
814 Views

Hi, I am trying to allocate an array for different data types using unlimited polymorphic. However, I find it difficult to pass the class(*),allocatable,intent(out) dummy argument to another subroutine with solid data type via "select type". The test code is listed below: (only implement "type is (integer)" as an example)

module m1
implicit none

contains

  subroutine s1(x)
    class(*),allocatable,intent(out),target :: x(:)
    select type(v => x)
      type is (integer)
        call s2(v)  ! s2(x) also fails
      class default
        stop 123
    end select
  end subroutine

  subroutine s2(x)
    integer,allocatable,intent(out) :: x(:)
    allocate(x, source = [1,2,3])
  end subroutine

end module

 Then, I encountered a compilation error: 

$ ifort -c m1.F90
m1.F90(12): error #7976: An allocatable dummy argument may only be argument associated with an allocatable actual argument.   [V]
        call s2(v)
----------------^
compilation aborted for m1.F90 (code 1)

How can I pass the argument and allocate it in the inner subroutine successfully?

 

Labels (1)
1 Solution
IanH
Honored Contributor II
781 Views

Further - the dynamic type of an unallocated object is never going to be integer.  You can replace the entire body of subroutine s1 with just 'stop 123'.

What are you trying to do?

View solution in original post

0 Kudos
7 Replies
FortranFan
Honored Contributor II
796 Views

@Roadelse ,

The standard does not permit what you seek.  The associate-name 'v' in your 's1' subprogram does NOT have the allocatable attribute.

If you delve further into the current language standard for Fortran and what it offers and the limitations that come along, you will find your attempt "to allocate an array for different data types using unlimited polymorphic" is not a good solution to whatever you are after in your program.

0 Kudos
Roadelse
Novice
768 Views

Thank you for the answer.

Therefore, I have to implement a subroutine with allocatable argument for each data type. 

0 Kudos
IanH
Honored Contributor II
782 Views

Further - the dynamic type of an unallocated object is never going to be integer.  You can replace the entire body of subroutine s1 with just 'stop 123'.

What are you trying to do?

0 Kudos
Roadelse
Novice
767 Views

Thanks for your reply.

I find you are right since I cannot pass a integer, allocatable array to this kind of subroutines ... ...

error #8300: If a dummy argument is allocatable or a pointer, and the dummy or its associated actual argument is polymorphic, both dummy and actual must be polymorphic with the same declared type or both must be unlimited polymorphic.

This error will be displayed

 

I was trying to "get" a unlimited polymorphic dynamic array within a derived type.

Now, it seems that I have to implement several subroutines for all data type one by one

0 Kudos
IanH
Honored Contributor II
751 Views

You *can* pass an integer allocatable array to an integer allocatable dummy argument (that's kind of the only argument you can pass in that circumstance) - but you don't have an integer allocatable array to pass.  The associating entity in a select type construct is not allocatable, as FortranFan says.  This is sensible, as otherwise you could reallocate the entity to have a different type inside the select type construct, and madness would result. 

(Avoiding similar "ha ha - changed the type!" nonsense is also why there is a requirement for matching declared types between dummy and actual if the dummy has the allocatable attribute.)

But... calling select type on an always unallocated object isn't going to do any useful "selection" - the only block that will be selected for execution is the one that best matches the declared type of the selector.   Your selector has a declared type of CLASS(*) - the best match if the selector is unallocated is going to be CLASS DEFAULT.  Hence - what are you trying to do?  Why are you calling SELECT TYPE?

Are you chasing something like:

  SUBROUTINE s3(x, desired_type)
    CLASS(*), INTENT(OUT), ALLOCATABLE :: x(:)
    CHARACTER(*), INTENT(IN) :: desired_type
    
    IF (desired_type == 'I want an integer') THEN
      BLOCK
        INTEGER, ALLOCATABLE :: tmp(:)
        CALL s2(tmp)
        x = tmp   ! or CALL MOVE_ALLOC(tmp, x)
      END BLOCK
    END IF
  END SUBROUTINE s3

Why is s2 a subroutine?  Can it be a function?  Imagine...

FUNCTION f2()
  INTEGER :: f2(3)
  f2 = [1, 2, 3]
END FUNCTION f2

Then the entire block construct in s3 above can be replaced with...

      x = f2()

 Do we even need a function?  The array is just a constant.

0 Kudos
Roadelse
Novice
740 Views

Thanks for you reply!

I forget the BLOCK grammar, it may also meet my requirement

0 Kudos
FortranFan
Honored Contributor II
684 Views

@Roadelse wrote:

..

Now, it seems that I have to implement several subroutines for all data type one by one


@Roadelse ,

It may help if you fully describe in plain words what you were asked earlier, "What are you trying to do?"

Ostensibly it appears you have recently discovered the support toward object-oriented paradigm in Fortran including its unlimited polymorphism semantics and you are now excited to use it (widely?) for certain generic programming tasks?  If so, you may want to rethink your approach, it's fraught.

Moreover with your statement above, "Now, it seems that I have to implement several subroutines for all data type one by one," it would appear you will help yourself with further analysis of what you are trying to do.

Given your statement, "I was trying to "get" a unlimited polymorphic dynamic array within a derived type," you may have been after something like the following (if so, you should still ask yourself why!) but you have now gone overboard when it comes to defining your "unlimited polymorphic dynamic array within a derived type"?

module m
   type :: t
      private
      class(*), allocatable :: foo(:)
   contains
      procedure :: init
      procedure :: output
   end type
contains
   subroutine init( this, x )
      class(t), intent(inout) :: this
      class(*), intent(in)   :: x(:)
      this%foo = x
   end subroutine
   subroutine output( this )
      class(t), intent(in) :: this
      character(len=*), parameter :: fmtg = "(*(g0:,1x))"
      select type ( foo => this%foo )
         type is ( integer )
            print fmtg, "integer foo: ", foo
         type is ( real )
            print fmtg, "real foo: ", foo
         type is ( character(len=*) )
            print fmtg, "string foo: ", foo
         class default 
      end select
   end subroutine
end module
   use m, only : t
   type(t) :: a
   call a%init( [1,2,3] )
   call a%output() 
   call a%init( [ -99.0, 99.0 ] )
   call a%output() 
   call a%init( [ "cat", "dog" ] )
   call a%output()
end 
C:\temp>ifort p.f /standard-semantics /free
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.9.0 Build 20230302_000000
Copyright (C) 1985-2023 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 14.34.31937.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:p.exe
-subsystem:console
p.obj

C:\temp>p.exe
integer foo:  1 2 3
real foo:  -99.00000 99.00000
string foo:  cat dog
0 Kudos
Reply