Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fortran Class (*) in Function Result

I am encountering an error with the function detailed in this post.

The problem occurs because I am trying to return a type corresponding to the input types. Can anyone suggest a solution? I originally had a function for each type, and then a generic interface to group them into the same name. Now I am trying to put everything in a single function using polymorphism.

Here is the error that gfortran is giving me.

gfortran -o build/lib/foul.o -c -ffree-form -g -J./build/lib lib/foul.f
lib/foul.f:471.45:

Function cassign (expr, a, b, wrn) Result (c)

I have tried to use an allocatable array. In the main program I then do

Character (len=65), Allocatable :: sc(:)
Integer, Allocatable :: ic(:)
Real, Allocatable :: rc(:)

Allocate (sc(1))
Allocate (ic(1))
Allocate (rc(1))

sc = cassign (ra < rb, sa, sb)
ic = cassign (ra < rb, ia, ib)
rc = cassign (ra < rb, ra, rb)

This returns the following error

gfortran -o build/utests/test_foul.o -c -ffree-form -g -J./build/lib utests/test_foul.f utests/test_foul.f:315.7:

sc = cassign (ra < rb, sa, sb)
     1
Error: Can't convert CLASS(*) to CHARACTER(1) at (1)
utests/test_foul.f:316.7:

ic = cassign (ra < rb, ia, ib)
     1
Error: Can't convert CLASS(*) to INTEGER(4) at (1)
utests/test_foul.f:317.7:

  rc = cassign (ra < rb, ra, rb)
       1
Error: Can't convert CLASS(*) to REAL(4) at (1)



                                         1
Error: CLASS variable 'c' at (1) must be dummy, allocatable or pointer
lib/foul.f:495.10:

      c = a
      1

Error: Nonallocatable variable must not be polymorphic in intrinsic
assignment at (1) -    check that there is a matching specific subroutine 
for '=' operator
lib/foul.f:497.10:

      c = b
      1

Here is the function I have coded. The variables a and b can be any of the types Character, integer or real. And the output type should match the inputs a and b The function type_match (a, b) returns true if the two types match, false otherwise.

Function cassign (expr, a, b, wrn) Result (c)

  Logical, Intent(in) :: expr
  Class (*), Intent(in) :: a, b
  Logical, Intent (out), Optional :: wrn

  Class (*) :: c  

  Logical :: warn, tma, tmb 

  !!$ Perform warning tests (performs type matching).
  If (Present (wrn)) Then

    !!$ Matching input types. 
    tma = type_match (a, b)
    if (tma) Then

      tmb = type_match (a, c)

      !!$ Matching input and output types.
      If (tmb) Then
        If (expr) Then
          c = a
        Else
          c = b
        End If
        wrn = .False.

      !!$ Warning: Non-matching types.
      Else
        wrn = .True.
      End If

    Else

      wrn = .True.

    End If

  Else

    If (expr) Then
      c = a
    Else
      c = b
    End If

  End If

End Function cassign
like image 298
Zeus Avatar asked Apr 15 '26 18:04

Zeus


1 Answers

I am not sure that I recommend doing what I write below, preferring instead keeping to generics, but I will attempt to explain.

The first thing to note is that, as the error message states, for a non-dummy argument polymorphic variable (such as c) that variable must have the pointer or allocatable attribute. Here, it makes sense for the function result to be allocatable.

After adding the allocatable attribute, you seem to experience two things related to assignment of the allocatable polymorphic variable: once in the function setting the result, and once using the result of the function.

The version of gfortran you are using doesn't (apparently) support intrinsic assignment to polymorphic variables. You can use the equivalent, which arguably has the intention even clearer:

allocate (c, source=a)  ! You may also need to provide bounds for c
                        ! for some gfortran.

This is the solution to the assignment problem in the function.

With the function result, however, you are now returning a polymorphic result. That means that the variable taking the assignment must also be polymorphic, or the assignment must not be intrinsic. This is the

Error: Can't convert CLASS(*) to INTEGER(4) at (1)

error when you try intrinsic assignment.

Either make everything polymorphic, stick with generics, or use defined assignment. A simplified example follows for the latter case. [Adjust and extend as required.]

module hello_bob
  interface assignment(=)
    module procedure int_equal_func_class
  end interface

contains

  subroutine int_equal_func_class(a,b)
    integer, intent(out) :: a(:)
    class(*), intent(in) :: b(:)

    select type (b)
      type is (integer)
        a = b
    end select
  end subroutine int_equal_func_class

   function func(a)
     class(*), intent(in) :: a(:)
     class(*), allocatable :: func(:)

     ! No intrinsic assignment supported, also see note about bounds
     allocate(func, source=a)
   end function func

end module hello_bob

program bob
  use hello_bob
  integer i(4)

  i=func([1,2,3,4])
  print*, i

end program bob
like image 72
francescalus Avatar answered Apr 18 '26 09:04

francescalus