Add a CONFORM function to check that argument dimensions match?

It is possible to check whether an optional argument has the right dimensions without using a nested loop, as shown in subroutine twice.

module m_mod
implicit none
contains
function first_false(tf) result(ipos)
logical, intent(in) :: tf(:)
integer             :: ipos
ipos = findloc(tf,.false.,dim=1)
end function first_false
!
subroutine twice(i,j,ierr)
integer, intent(in)            :: i(:,:)
integer, intent(out), optional :: j(:,:)
integer, intent(out)           :: ierr 
ierr = 0
if (present(j)) ierr = first_false(shape(i)==shape(j)) ! test that optional argument j conforms with i
if (ierr == 0 .and. present(j)) j = 2*i
end subroutine twice

subroutine thrice(i,j,ierr) ! more verbose
integer, intent(in)            :: i(:,:)
integer, intent(out), optional :: j(:,:)
integer, intent(out)           :: ierr 
ierr = 0
if (present(j)) then
   if (size(i,1) /= size(j,1)) then
      ierr = 1
   else if (size(i,2) /= size(j,2)) then
      ierr = 2
   end if
   if (ierr /= 0) return
   j = 3*i
end if
end subroutine thrice
end module m_mod
!
program main
use m_mod, only: twice
implicit none
integer :: i(2,3),j(2,2),k(2,3),ierr
i = 5
call twice(i,j,ierr)
print*,"ierr=",ierr
call twice(i,ierr=ierr)
print*,"ierr=",ierr
call twice(i,k,ierr)
print*,"ierr=",ierr
print*,"k=",k
end program main

Running this gives

 ierr=           2
 ierr=           0
 ierr=           0
 k=          10          10          10          10          10          10
1 Like

I discovered this post thanks to @awvwgk (from type(*): token type '*' is unexpected here (#439) · Issues · lfortran / lfortran · GitLab). What does type(*) mean? For example in:

function conform(mold, val, dim)
   type(*), intent(in) :: mold(..)
   type(*), intent(in), optional :: val(..)
   integer, intent(in), optional :: dim
   logical :: conform
...
end function

how can one use the mold variable? What if I want to read the first element of this array, and check if it is an integer and equal to 1. How do I do that?

@certik, you will recall type(*) is the other unlimited polymorphic option introduced starting Fortran 2018 that facilitates certain scenarios involving void * during interoperability with C.

You can see this comment upthread, there are very limited instructions one can perform with type(*) dummy arguments in Fortran.

Standard conformance would imply one cannot “read the first element of this array, and check if it is an integer and equal to 1”

1 Like

Thanks @FortranFan ! I was actually going to propose to implement type(*) as an extension in LFortran to make it easier to write generic interfaces, such as the intrinsic size function:

interface
    integer function size(x)
    type(*), intent(in) :: x(..)
    end function
end interface

And I now realized this is already in standard Fortran!

Why not to extend this natural syntax to actually make it useful and be able to do stuff with it somehow, such as read the first element?

The pushback you’ll receive with that is the language already has class(*) the other unlimited polymorphic option for such situations.

Looking at type(*), it would appear it’s geared for semantics of a pass-through address in procedure references, an opaque void * pointer i.e., a typeless entity for which, say, an implementation won’t need to cough up any descriptors. With such a design already in place in the language standard with Fortran 2018, it seems rather difficult to do much with it but I could be wrong.

1 Like