Silverfrost Forums

Welcome to our forums

Allocate on assignment + CHARACTER variables + TRANSFER

27 Apr 2023 11:29 #30235

I think there is an issue with the new Fortran 2003 Allocate on assignment for CHARACTER variables, when the array is defined by the result of the TRANSFER intrinsic.

Having never used TRANSFER before this evening it's definitely not a critical issue of me. Just experimenting after getting a little bit further into one of the (now old) text books by Metcalf and Reid.

program t
implicit none
character(len=1), allocatable :: info(:)
integer                       :: lengthData
real                          :: r = 5.0
real                          :: x = -999.0

!
! This works in FTN95
!
  info=['A','B','C']                    ! Allocate on assignment works in this case 
  print*, 'Info = ', info
  deallocate(info)
  print*
                                        ! Now use TRANSFER intrinsic
                                        
  print*, 'Value of R is  ', r          ! 1. Print value of R
  lengthData = size(transfer(r, info))  ! 2. Find size of required character array
  allocate(info(lengthData))            ! 3. Allocate array
  info = transfer(r, info)              ! 4. Do transfer R to array
  print*, 'Size of array  ',size(info)  ! 5. Print size of array
  print*, 'Info string is ',info        ! 6. Print array
  x = transfer(info,r)                  ! 7. Do transfer array to X
  print*, 'Value of X is  ', x          ! 8. Print value of X
  deallocate(info)
  print*
!
! This alternative fails in FTN95 where steps 2, 3 and 4 are done
! in a single line of code
!
  x = -999.0
  print*, 'Value of R is  ', r          ! 1. Print value of R 
  info = transfer(r,info)               !    Access violation occurs here ###
  print*, 'Size of array  ',size(info)  ! 5. Print size of array
  print*, 'Info string is ',info        ! 6. Print array
  x = transfer(info,r)                  ! 7. Do transfer array to X
  print*, 'Value of X is  ', x          ! 8. Print value of X
  deallocate(info)
end program t
28 Apr 2023 6:51 #30237

Ken

Thanks for the feedback.

This sample code does not produce sensible results when compiled with gFortran or iFort so I am guessing that there is something wrong with it.

I am not that familiar with the TRANSFER function and at first sight I don't understand what is intended.

28 Apr 2023 10:46 #30238

Thanks Paul,

I have set myself the task of investigating parts of the language which I never used before, and I may be going a bit of course here.

The code should be equivalent to the single line X=R, which is achieved in the first part of the example with FTN95. Basically R is TRANSFERed to the character array INFO, and then TRANSFERed from INFO to X.

The printed output for INFO is meaningless. I cannot figure out how to print the bit pattern for the elements of INFO to the terminal, as in:

character(len=1) :: a(3) = ['A','B','C']
print'(3B8)', a(1), a(2), a(3)
end

Should this not return: 1000001 1000010 1000011 ?

Binary 1000001 = 65 in decimal, IACHAR('A') = 65

Perhaps the use of the B format code to characters is a recent addition to the language, or an extension in gFortran?

PS Sometime later I asked myself another 'what happens if' question:

program p
integer, parameter :: sp = kind(1.0), dp=kind(1.d0)
real(sp)    :: rs = 1.0
real(dp)    :: rd = 1.d0
complex(sp) :: cs =cmplx(1.0,0.0)
complex(dp) :: cd =cmplx(1.d0,0.d0,kind=dp) 
print'(A,B32)' , 'rs',rs
print'(A,B64)' , 'rd',rd
print'(A,2B32)', 'cs',cs
print'(A,2B64)', 'dc',cd
end program p

This is valid in gFortran.

28 Apr 2023 1:39 #30242

Ken

When I see

lengthData = size(transfer(r, info))

I ask what is transfer(r, info)? r is REAL and contains the floating point representation of the single precision 5.0. The result has the same bit pattern as this but with the type changed to that of info. But then info is a 1-dimensional CHARACTER array of unknown length.

Is this meaningful and what its intended?

28 Apr 2023 3:36 #30245

Paul, firstly apologies for taking up your time.

TRANSFER (SOURCE, MOLD [, SIZE])

According to Metcalf:

“ …. when SIZE is absent, the result is scalar if MOLD is scalar, and it is of rank one and size just sufficient to hold all of SOURCE if MOLD is array-valued.”

The draft Fortran 95 standard says:

“If MOLD is array valued and SIZE is absent, the result is array valued and of rank one. Its size is as small as possible such that its physical representation is not shorter than that of SOURCE

I think these two extracts both have the same meaning, and imply that lengthData = size(transfer(r, info)) is a valid Fortran construction.

The form: lengthData = size(transfer(r, info)) also appears in this discussion of a generic linked list module implemented in Fortran 95:

https://jblevins.org/research/generic-list.pdf

In this case MOLD is integer, but the type of MOLD does not matter for the purpose of storing a collection of bits.

However, even with info defined as integer(kind=1), (which is probably more logical and fixes the problem printing the bit pattern), the allocate on assignment still fails.

program t2
implicit none
integer(kind=1), allocatable :: info(:)
integer                      :: lengthData,i
real                         :: r = 5.0
real                         :: x = -999.0

  print*, 'Value of R is  ', r          ! 1. Print value of R
  lengthData = size(transfer(r, info))  ! 2. Find size of required character array
  allocate(info(lengthData))            ! 3. Allocate array
  info = transfer(r, info)              ! 4. Do transfer R to array
  print*, 'Size of array  ',size(info)  ! 5. Print size of array
  do i = 1, lengthData                  ! 6. Print array
    print'(B8)', info(i)
  end do  
  x = transfer(info,r)                  ! 7. Do transfer array to X
  print*, 'Value of X is  ', x          ! 8. Print value of X
  deallocate(info)
  print*
  
  print*, 'Value of R is  ', r                   ! 1. Print value of R 
  info = transfer(r,info)                        ! 2, 3, 4 
  print*, 'Size of array  ',size(info)           ! 5. Print size of array
  print*, 'Info string (bit pattern) is '        ! 6. Print array
  do i = 1, size(info)
    print'(B8)', info(i)
  end do
  x = transfer(info,r)                           ! 7. Do transfer array to X
  print*, 'Value of X is  ', x                   ! 8. Print value of X
  deallocate(info)
end program t2

Enjoy the weekend and don’t worry about the TRANSFER intrinsic, the dearth of information google finds on this subject tells me its little used.

28 Apr 2023 7:21 #30246

Ken

I am beginning to understand what is expected. The C language has sizeof and Fortran 2008 has C_SIZEOF and this could provide a simpler approach.

29 Apr 2023 6:56 #30248

Here is a sample that illustrates the concept...

program main
use iso_c_binding
integer,parameter::k=selected_int_kind(2)
integer(k),allocatable::info(:)
integer(k)::v
integer::r = 16+256+1024
isize = c_sizeof(r)/c_sizeof(v)
print*, k, isize
allocate(info(isize))
info = transfer(r, info)
write(*,'(z6)') r
print*, '=============='
do i=isize,1,-1
  write(*, '(z6)') info(i)
end do  
end program main

On this basis it might be relatively easy to get FTN95 to do the 'allocate on assignment' for the TRANSFER function.

30 Apr 2023 11:16 #30250

Paul,

Thanks for the sample program, it took me some time to understand the code.

My main concern here was to highlight that the new feature i.e. allocate on assignment failed with TRANSFER.

As there is an easy alternative work around (find the required SIZE and ALLOCATE before TRANSFER), and the probability of another user finding this particular issue must be relatively low, perhaps this fix should be deferred to a low position on the wish list i.e. one for when available time/resources permit. In other words, nice to have but not a priority.

Enjoy what remains of the long bank holiday weekend.

30 May 2023 1:06 #30364

FTN95 has now been extended for the next release so that it will handle this 'allocate on assignment' (AOA) for the TRANSFER intrinsic.

Note that, by default, FTN95 does not do AOA when the associated variable is explicitly ALLOCATEd (in the current subprogram) prior to the assignment.

This provides some protection against the impact of AOA on existing code.

So the explicit ALLOCATE in the above code will prevent the following AOA.

Please login to reply.