Difference between passing a number and a variable to a subroutine

  • Follow


Hello everyone!
I just found out that Fortran distinguishes between passing a variable 
and actual numbers to a subroutine.

F.eks. writing

integer, dimension(2) ddims
ddims(1) = 64
ddims(2) = 64
CALL h5dread_f(dset1_id, H5T_NATIVE_DOUBLE, bufnew, ddims, error)

works perfectly, but

CALL h5dread_f(dset1_id, H5T_NATIVE_DOUBLE, bufnew, (/64,64/), error)

results in a compiler error: ( I am using the intel fortran compiler v. 
11.1)
../initl.f90(175): error #6285: There is no matching specific subroutine
for this generic subroutine call.   [H5DREAD_F]
         call h5dread_f(dset_id, H5T_NATIVE_DOUBLE, theta(1:My, 1:Nx),
(/My,Nx/), error)

So when I declare and initialize the array, the call works, but passing
the same numbers instead results in an error.

Coming from the C/Python world this rather astonishes me. Is this 
because in Fortran subroutines get a reference rather than a value 
passed by default?
I would have also expected a segfault when passing a wrong reference
rather then a compiler error.
Can anybody enlighten me?

Cheers, Ralph
0
Reply Ralph 12/1/2009 10:26:36 AM

Hi Ralph,

Unlike C, Fortran passes its procedure parameters by reference. So an
array literal will only work as an argument procedure declared intent
(in). For example, the code below will not compile with the second
call to foo uncommented - unless the dummy argument x of foo is
declared intent(in).

module m

  public :: foo

  contains

  function foo(x) result(y)
    integer, dimension(:), intent(inout) :: x
    integer, dimension(size(x))       :: y
    y = x + 1
  end function foo

end module m

program main

  use m
  integer, dimension(4) :: f = 19, g
!  g = foo( f )
  g = foo( (/19,19,19,19/) )

  print *, f
  print *, g

end program main

You will get a similar issue in C++ when calling "bar" with a literal
(it needs a "const" qualifier)
  int bar(int &x){ return 9; }

Cheers,
Graham

0
Reply PGK 12/1/2009 12:59:43 PM


"Ralph Kube" <rku000@post.uit.no> wrote in message 
news:hf2r0i$o31$1@inn.uit.no...

> I just found out that Fortran distinguishes between passing a variable and 
> actual numbers to a subroutine.

> integer, dimension(2) ddims
> ddims(1) = 64
> ddims(2) = 64
> CALL h5dread_f(dset1_id, H5T_NATIVE_DOUBLE, bufnew, ddims, error)

> works perfectly, but

> CALL h5dread_f(dset1_id, H5T_NATIVE_DOUBLE, bufnew, (/64,64/), error)

> results in a compiler error: ( I am using the intel fortran compiler v. 
> 11.1)
> ./initl.f90(175): error #6285: There is no matching specific subroutine
> for this generic subroutine call.   [H5DREAD_F]
>         call h5dread_f(dset_id, H5T_NATIVE_DOUBLE, theta(1:My, 1:Nx),
> (/My,Nx/), error)

Probably a simple mistake on your part.  Can you give us the
declarations of dset1_id, H5T_NATIVE_DOUBLE, bufnew, error, dset_id,
and theta?  Also the specification parts of the specific subroutines
which generic h5dread_f may resolve to?

-- 
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


0
Reply James 12/1/2009 3:51:15 PM

Ralph Kube <rku000@post.uit.no> wrote:

> I just found out that Fortran distinguishes between passing a variable
> and actual numbers to a subroutine.
> 
> F.eks. writing
> 
> integer, dimension(2) ddims
> ddims(1) = 64
> ddims(2) = 64
> CALL h5dread_f(dset1_id, H5T_NATIVE_DOUBLE, bufnew, ddims, error)
> 
> works perfectly, but
> 
> CALL h5dread_f(dset1_id, H5T_NATIVE_DOUBLE, bufnew, (/64,64/), error)
> 
> results in a compiler error: ( I am using the intel fortran compiler v.
> 11.1)
> ./initl.f90(175): error #6285: There is no matching specific subroutine
> for this generic subroutine call.   [H5DREAD_F]
>          call h5dread_f(dset_id, H5T_NATIVE_DOUBLE, theta(1:My, 1:Nx),
> (/My,Nx/), error)
> 
> So when I declare and initialize the array, the call works, but passing
> the same numbers instead results in an error.

I'd like to see a complete sample, including the subroutine and the
generic inerface block. One could cut things way down to make such a
sample, as the subroutine doesn't actually have to do anything. I'm
wondering if the problem doesn't lie in something not shown.

After all, when an error message complains about the specific
subroutines, it naturally makes me want to see those subroutines in
order to diagnose things.

There are differences between passing a variable and an expression as an
actual argument (the above array constant is just a trivial case of an
expression), but they are not differences that should affect generic
resolution. They just have to do with the INTENT attribute. An
expression is not modifiable and cannot be an actual argument for an
INTENT(OUT) or INTENT(INOUT) dummy. (The case of unspecified intent can
be messier). I suppose one possibility is that you might have an
inappropriate INTENT attribute for an expression actual argument. If
that were so, this error message would be a little misleading, but
that's something I could believe.

I hesitate to even mention the possibility of a compiler bug without
seeing a complete sample. It is too easy for there to be other
unconsidered factors. The above INTENT question is one that immediately
occurs to me, but there could be others that I didn't think of.

P.S. Completely irrelevant, but when I first saw the H5... in the actual
argument lists, I inadvertantly mentally transposed that to 5H... and
groaned at the thought of Hollerith actual arguments mixed with generic
resolution. If you never programmed in f66, you might not have any idea
what I'm talking about. That's ok, as it really is irrelevant. Nothing
wrong with your code in that regard. I just thought some other "old
timers" might understand my reaction and find it mildly humorous.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam 12/1/2009 5:18:05 PM

PGK wrote:
> Hi Ralph,
> 
> Unlike C, Fortran passes its procedure parameters by reference. So an
> array literal will only work as an argument procedure declared intent
> (in). For example, the code below will not compile with the second
> call to foo uncommented - unless the dummy argument x of foo is
> declared intent(in).
> 
Two things wrong here.  Fortran does NOT pass procedure arguments
by reference.  The standard is silent on how arguments are passed.
Many compilers choose to implement a scheme that is similar to
call by reference.  But, there are differences and many (most? all?)
compilers use a scheme that is essentially copy-in/copy-out
for scalar arguments.

Second, it is not necessary to specify INTENT for dummy arguments,
constant or not.  It's usually a good idea, but it's not required
when actual arguments are literal constants.  The rule is that
you are not allowed to change a dummy argument that is associated
with a literal constant (or with any of a few other things).
INTENT can often help detect mistakes, but you have to do the
right thing regardless of any declarations.

Dick Hendrickson

> module m
> 
>   public :: foo
> 
>   contains
> 
>   function foo(x) result(y)
>     integer, dimension(:), intent(inout) :: x
>     integer, dimension(size(x))       :: y
>     y = x + 1
>   end function foo
> 
> end module m
> 
> program main
> 
>   use m
>   integer, dimension(4) :: f = 19, g
> !  g = foo( f )
>   g = foo( (/19,19,19,19/) )
> 
>   print *, f
>   print *, g
> 
> end program main
> 
> You will get a similar issue in C++ when calling "bar" with a literal
> (it needs a "const" qualifier)
>   int bar(int &x){ return 9; }
> 
> Cheers,
> Graham
> 
0
Reply Dick 12/1/2009 9:23:56 PM

In article <7nlfreF3m6cahU1@mid.individual.net>, Dick Hendrickson
<dick.hendrickson@att.net> writes: 

> > Unlike C, Fortran passes its procedure parameters by reference. So an
> > array literal will only work as an argument procedure declared intent
> > (in). For example, the code below will not compile with the second
> > call to foo uncommented - unless the dummy argument x of foo is
> > declared intent(in).
> > 
> Two things wrong here.  Fortran does NOT pass procedure arguments
> by reference.  The standard is silent on how arguments are passed.
> Many compilers choose to implement a scheme that is similar to
> call by reference.  But, there are differences and many (most? all?)
> compilers use a scheme that is essentially copy-in/copy-out
> for scalar arguments.

I think that, for most purposes, one can imagine that things are AS IF
the compiler passed arguments by reference. 

> Second, it is not necessary to specify INTENT for dummy arguments,
> constant or not.  It's usually a good idea, but it's not required
> when actual arguments are literal constants.  The rule is that
> you are not allowed to change a dummy argument that is associated
> with a literal constant (or with any of a few other things).
> INTENT can often help detect mistakes, but you have to do the
> right thing regardless of any declarations.

One can change a dummy argument that is associated with a variable.  
However, this might not be what you want to do.  Using INTENT (properly, 
of course) can help detect some errors where the code would otherwise be 
legal but might not have the intended effect.

I seem to remember that passing (X) instead of X could be used as a poor
man's INTENT(IN) since the parentheses mean that it is an expression
which must be evaluated, and hence a constant (i.e. the result of the
evaluation) will be passed.  Can one depend on this to work?  (Actually, 
probably the constant itself is not passed, but rather the result of the 
evaluation is put into READ-ONLY memory and the address of that is 
passed.)

0
Reply helbig 12/1/2009 9:38:28 PM

Dick Hendrickson <dick.hendrickson@att.net> wrote:

> PGK wrote:

> > So an
> > array literal will only work as an argument procedure declared intent
> > (in). For example, the code below will not compile with the second
> > call to foo uncommented - unless the dummy argument x of foo is
> > declared intent(in).
> > 
> Two things wrong here.... 
> Second, it is not necessary to specify INTENT for dummy arguments,
> constant or not.  It's usually a good idea, but it's not required
> when actual arguments are literal constants.  The rule is that
> you are not allowed to change a dummy argument that is associated
> with a literal constant (or with any of a few other things).
> INTENT can often help detect mistakes, but you have to do the
> right thing regardless of any declarations.

To illustrate that, I took the code shown and removed the INTENT
specification. It compiled (and ran) correctly with both compilers I
have installed on this machine.

So no, you don't have to have INTENT(IN). It is a good idea, but you
don't actually have to do it. What you have to do is not have
intent(inout) (or intent(out), but that wouldn't fit here for other
reasons). A more accurate statement might be that the only intent you
are allowed to specify is INTENT(IN), but that unspecified intent still
works, even if perhaps ill-advised.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam 12/1/2009 9:50:02 PM

Phillip Helbig---undress to reply <helbig@astro.multiCLOTHESvax.de>
wrote:

> In article <7nlfreF3m6cahU1@mid.individual.net>, Dick Hendrickson
> <dick.hendrickson@att.net> writes: 

> > Fortran does NOT pass procedure arguments
> > by reference.

> I think that, for most purposes, one can imagine that things are AS IF
> the compiler passed arguments by reference. 

Since imagining that quite regularly results in buggy code, I think not.
Examples abound of bugs from imagining that way. They are a class of
bugs that sometimes show up only when you turn on optimization. In
particular, if you imagine that, you will naturally expect to be able to
change the value of one dummy argument and have that change immediately
reflected in anything else that dummy argument is associated with;
that's exactly what a pass by reference would imply. If you aren't
imagining that, then you aren't really imagining pass by reference.

I would say it was far more accurate to say that for most purposes, you
should avoid imagining the implementation details of how arguments are
passed at all. If your code actually depends on those details, then the
code is probably buggy anyway. C interop is an exception.

> I seem to remember that passing (X) instead of X could be used as a poor
> man's INTENT(IN) since the parentheses mean that it is an expression
> which must be evaluated, and hence a constant (i.e. the result of the
> evaluation) will be passed.  Can one depend on this to work?  (Actually,
> probably the constant itself is not passed, but rather the result of the
> evaluation is put into READ-ONLY memory and the address of that is 
> passed.)

No. There are tricks related to passing (X) instead of X, but they do
not have at all the same effect as intent(in). Yes, you can (usually)
count on them to work; the standard says they will. Compilers have been
known to have bugs in that area, but I think those bugs have tended to
be fixed. But "working" does not mean that this is much like
iintent(in). It does things that intent(in) doesn't do, and it doesn't
do things that intent in does. So pretty much, no, they aren't alike. It
is much closer to the f2003 VALUE attribute.

For things that it doesn't do, but intent(in) does: It doesn't give
error messages. There is no guarantee that you will get an error message
from erroneously attempting to modify a dummy whenthe actual is (X). It
is an error, but there is no guarantee that you will get an error
message.

For things that it does, but intent(in) doesn't: It avoids aliasing and
thus allows you to modify other arguments that might otherwise be
aliased. Intent(in) doesn't do that.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam 12/1/2009 10:11:02 PM

Ralph Kube wrote:

> CALL h5dread_f(dset1_id, H5T_NATIVE_DOUBLE, bufnew, (/64,64/), error)
> 
> results in a compiler error: ( I am using the intel fortran compiler v. 
> 11.1)
> ./initl.f90(175): error #6285: There is no matching specific subroutine
> for this generic subroutine call.   [H5DREAD_F]
>         call h5dread_f(dset_id, H5T_NATIVE_DOUBLE, theta(1:My, 1:Nx),
> (/My,Nx/), error)

I tried to construct an example to reproduce this problem, but couldn't. 
  The comments about INTENT are interesting but not relevant as INTENT 
does not play in generic resolution, which is what this error message is 
about.

There's an interesting thing here.  Compare the call that Ralph says he 
used with the one displayed in the error message - they are quite 
different.  If I had to guess (and I do), I'd say that My and Nx are not 
default integer.

-- 
Steve Lionel
Developer Products Division
Intel Corporation
Nashua, NH

For email address, replace "invalid" with "com"

User communities for Intel Software Development Products
   http://software.intel.com/en-us/forums/
Intel Software Development Products Support
   http://software.intel.com/sites/support/
My Fortran blog
   http://www.intel.com/software/drfortran
0
Reply Steve 12/2/2009 1:45:58 AM

"Steve Lionel" <steve.lionel@intel.invalid> wrote in message 
news:7nlv68F3lc1jtU1@mid.individual.net...

> There's an interesting thing here.  Compare the call that Ralph says he 
> used with the one displayed in the error message - they are quite 
> different.  If I had to guess (and I do), I'd say that My and Nx are not 
> default integer.

I am cheering for dset_id to be undeclared and not a TKR match for
dset1_id.

-- 
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


0
Reply James 12/2/2009 1:55:04 AM

Steve Lionel <steve.lionel@intel.invalid> wrote:

> There's an interesting thing here.  Compare the call that Ralph says he
> used with the one displayed in the error message - they are quite 
> different.

Excellent point. I missed that. Makes me even more want to see an actual
complete sample, since the tidbits reported seem internally
inconsistent. I'm inclined to guess this is yet another case of telling
us what he thought was wrong instead of showing the original data.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam 12/2/2009 4:04:50 AM

In article <1ja1t4c.1ynd899uez7swN%nospam@see.signature>,
 nospam@see.signature (Richard Maine) wrote:

> Since imagining that quite regularly results in buggy code, I think not.

I agree with this.  You should "imagine" that everything is passed 
by address and make sure that your code works that way, and then you 
should "imagine" that everything is passed by copy-in/copy-out and 
make sure your code works that way too (when appropriate).  And 
consider the consequences to your code if arguments are passed 
through registers without addresses, and so on.  This results in 
code that is consistent with the standard, which is silent on 
specifying argument passing mechanisms, so it should result in code 
that is as portable as possible.  This idea of making your code 
bulletproof to all possible argument passing methods needs to be 
extended and/or modified a little bit when some of the newer 
attributes are considered, such as pointer, target, allocatable, and 
various INTENTs.

If, for some reason, your code depends on something particular in 
this respect, and you can't accomplish the goal any other way, then 
at least the requirements should be documented so that the next 
programmer (which might be you six months from now) understands what 
is happening.

$.02 -Ron Shepard
0
Reply Ron 12/2/2009 6:29:13 AM

Hi Richard, here is the complete data.
It is a modified example program from the HDF5 software.
When i exchange the call in line 81

CALL h5dread_f(dset1_id, H5T_NATIVE_DOUBLE, bufnew, data_dims, error)

with

CALL h5dread_f(dset1_id, H5T_NATIVE_DOUBLE, bufnew, (/64,64/), error)


i get a compiler error:

selectele2.f90(81): error #6285: There is no matching specific 
subroutine for this generic subroutine call.   [H5DREAD_F]
       CALL h5dread_f(dset1_id, H5T_NATIVE_DOUBLE, bufnew, (/64,64/), error)
-----------^
compilation aborted for selectele2.f90 (code 1)

To better understand how Fortran works I am curious to find out what
the reason for this behaviour is.

Cheers, Ralph


! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
* * * *
!   Copyright by The HDF Group. 
       *
!   Copyright by the Board of Trustees of the University of Illinois. 
       *
!   All rights reserved. 
       *
! 
       *
!   This file is part of HDF5.  The full HDF5 copyright notice, 
including     *
!   terms governing use, modification, and redistribution, is contained 
in    *
!   the files COPYING and Copyright.html.  COPYING can be found at the 
root   *
!   of the source code distribution tree; Copyright.html can be found at 
the  *
!   root level of an installed copy of the electronic HDF5 document set 
and   *
!   is linked from the top-level documents page.  It can also be found 
at     *
!   http://hdfgroup.org/HDF5/doc/Copyright.html.  If you do not have 
       *
!   access to either file, you may request a copy from 
help@hdfgroup.org.     *
! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
* * * *
!
!
!            This program creates two files, copy1.h5, and copy2.h5.
!            In copy1.h5, it creates a 3x4 dataset called 'Copy1',
!            and write 0's to this dataset.
!            In copy2.h5, it create a 3x4 dataset called 'Copy2',
!            and write 1's to this dataset.
!            It closes both files, reopens both files, selects two
!            points in copy1.h5 and writes values to them.  Then it
!            uses an H5Scopy to write the same selection to copy2.h5.
!            Program reopens the files, and reads and prints the 
contents of
!            the two datasets.
!

       PROGRAM SELECTEXAMPLE

       USE HDF5 ! This module contains all necessary modules

       IMPLICIT NONE

       CHARACTER(LEN=11), PARAMETER :: filename1 = "output.hdf5" ! File name
       CHARACTER(LEN=5), PARAMETER :: dsetname1 = "O/002"    ! Dataset name
       CHARACTER(LEN=20) :: name_buffer

       INTEGER, PARAMETER :: RANK = 2 ! Dataset rank

       INTEGER(SIZE_T), PARAMETER :: NUMP = 2 ! Number of points selected

       INTEGER(HID_T) :: file1_id       ! File1 identifier
       INTEGER(HID_T) :: dset1_id       ! Dataset1 identifier
       INTEGER(HID_T) :: dataspace1     ! Dataspace identifier
       INTEGER(HID_T) :: memspace       ! memspace identifier

       INTEGER(HSIZE_T), DIMENSION(1) :: dimsm = (/2/)
                                                     ! Memory dataspace 
dimensions
       INTEGER(HSIZE_T), DIMENSION(2) :: dimsf = (/64,64/)
                                                     ! File dataspace 
dimensions
       INTEGER(HSIZE_T), DIMENSION(RANK,NUMP) :: coord ! Elements 
coordinates
                                                        ! in the file

       real(kind=8), DIMENSION(64,64) :: bufnew ! Data buffers
       INTEGER, DIMENSION(2) :: val = (/53, 59/) ! Values to write

       INTEGER :: memrank = 1  ! Rank of the dataset in memory

       INTEGER :: i, j

       INTEGER :: error  ! Error flag
       INTEGER :: nmembers, htype
       LOGICAL :: status
       INTEGER(HSIZE_T), DIMENSION(2) :: data_dims

       CALL h5open_f(error)

! Open the files.
       print*, filename1
       CALL h5fopen_f (filename1, H5F_ACC_RDWR_F, file1_id, error)

       ! Open the  datasets.
       print*, dsetname1
       CALL h5dopen_f(file1_id, dsetname1, dset1_id, error)

       ! Read dataset from the first file.
       data_dims(1) = 64
       data_dims(2) = 64
       print*, data_dims
       CALL h5dread_f(dset1_id, H5T_NATIVE_DOUBLE, bufnew, data_dims, error)

       ! Display the data read from dataset "Copy1"
       write(*,*) "The data in dataset Copy1 is: "
       do i = 1, 64
           print*, i
           print *, (bufnew(i,j), j = 1,64)
       end do

       ! Close datasets.
       CALL h5dclose_f(dset1_id, error)

       ! Get number of members in the root group.
       CALL h5gn_members_f(file1_id, "O", nmembers, error)
       write(*,*) "Number of root group member is " , nmembers

       ! Print each group member's name and type.
       do i = 0, nmembers - 1
         CALL h5gget_obj_info_idx_f(file1_id, "/O/", i, name_buffer, 
htype, &
                                      error)
         write(*,*) name_buffer, htype
       end do
       ! Close files.
       CALL h5fclose_f(file1_id, error)

       print*, 'files closed'
       ! Close FORTRAN interface.
       CALL h5close_f(error)

       END PROGRAM SELECTEXAMPLE


Richard Maine wrote:
> Steve Lionel <steve.lionel@intel.invalid> wrote:
> 
>> There's an interesting thing here.  Compare the call that Ralph says he
>> used with the one displayed in the error message - they are quite 
>> different.
> 
> Excellent point. I missed that. Makes me even more want to see an actual
> complete sample, since the tidbits reported seem internally
> inconsistent. I'm inclined to guess this is yet another case of telling
> us what he thought was wrong instead of showing the original data.
> 
0
Reply Ralph 12/2/2009 9:16:58 AM

I just dug and found the h5dread_f subroutine:

           SUBROUTINE h5dread_reference_obj(dset_id, mem_type_id, buf, 
dims, hdferr, &
                                         mem_space_id, file_space_id, 
xfer_prp)
             IMPLICIT NONE
             INTEGER(HID_T), INTENT(IN) :: dset_id   ! Dataset identifier
             INTEGER(HID_T), INTENT(IN) :: mem_type_id ! Memory datatype 
identifier
             INTEGER(HSIZE_T), INTENT(IN), DIMENSION(*) :: dims
             TYPE(hobj_ref_t_f), INTENT(INOUT) , &
             DIMENSION(dims(1)) :: buf
             INTEGER, INTENT(OUT) :: hdferr      ! Error code
             INTEGER(HID_T), OPTIONAL, INTENT(IN) :: mem_space_id
                                                 ! Memory dataspace 
identfier
             INTEGER(HID_T), OPTIONAL, INTENT(IN) :: file_space_id
                                                 ! File dataspace identfier
             INTEGER(HID_T), OPTIONAL, INTENT(IN) :: xfer_prp
                                                 ! Transfer property 
list identifier

             INTEGER(HID_T) :: xfer_prp_default
             INTEGER(HID_T)  :: mem_space_id_default
             INTEGER(HID_T) :: file_space_id_default
             INTEGER(HADDR_T), ALLOCATABLE, DIMENSION(:) :: ref_buf
             INTEGER :: j

!            INTEGER, EXTERNAL :: h5dread_ref_obj_c
! MS FORTRAN needs explicit interface for C functions called here.
!
             INTERFACE
               INTEGER FUNCTION h5dread_ref_obj_c(dset_id, mem_type_id,&
                                                   mem_space_id_default, &
                                file_space_id_default, xfer_prp_default, 
ref_buf, dims)
               USE H5GLOBAL
               !DEC$IF DEFINED(HDF5F90_WINDOWS)
               !DEC$ATTRIBUTES 
C,reference,decorate,alias:'H5DREAD_REF_OBJ_C'::h5dread_ref_obj_c
               !DEC$ENDIF
               INTEGER(HID_T), INTENT(IN) :: dset_id
               INTEGER(HID_T), INTENT(IN) :: mem_type_id
               INTEGER(HID_T) :: xfer_prp_default
               INTEGER(HID_T)  :: mem_space_id_default
               INTEGER(HID_T) :: file_space_id_default
               INTEGER(HSIZE_T), INTENT(IN), DIMENSION(*) :: dims
               INTEGER(HADDR_T), DIMENSION(*) :: ref_buf
               END FUNCTION h5dread_ref_obj_c
             END INTERFACE

             allocate(ref_buf(dims(1)), stat=hdferr)
             if (hdferr .NE. 0) then
                 hdferr = -1
                 return
             endif

             xfer_prp_default = H5P_DEFAULT_F
             mem_space_id_default = H5S_ALL_F
             file_space_id_default = H5S_ALL_F

             if (present(xfer_prp)) xfer_prp_default = xfer_prp
             if (present(mem_space_id))  mem_space_id_default = 
mem_space_id
             if (present(file_space_id)) file_space_id_default = 
file_space_id

             hdferr = h5dread_ref_obj_c(dset_id, mem_type_id, 
mem_space_id_default, &
                                 file_space_id_default, 
xfer_prp_default, ref_buf, dims)
              do j = 1, dims(1)
                 buf(j)%ref = ref_buf(j)
              enddo
              deallocate(ref_buf)
           END SUBROUTINE h5dread_reference_obj
0
Reply Ralph 12/2/2009 9:31:48 AM

James Van Buskirk wrote:
> Probably a simple mistake on your part.  Can you give us the
> declarations of dset1_id, H5T_NATIVE_DOUBLE, bufnew, error, dset_id,
> and theta?  Also the specification parts of the specific subroutines
> which generic h5dread_f may resolve to?

I posted a working example in another subthread. It is a modified
example program from the HDF5 distribution ( as I observed the problem
when working with it).
I was looking for the definition of H5T_NATIVE_DOUBLE, but
could not find it in the HDF5 package. I think it translates to the
machine native floating point number, so to a ieee-754 64 bit floating 
point number on a pentium-d.

Cheers, Ralph

0
Reply Ralph 12/2/2009 9:40:33 AM

Ron Shepard wrote:
> I agree with this.  You should "imagine" that everything is passed 
> by address and make sure that your code works that way, and then you 
> should "imagine" that everything is passed by copy-in/copy-out and 
> make sure your code works that way too (when appropriate).  And 
> consider the consequences to your code if arguments are passed 
> through registers without addresses, and so on.  This results in 
> code that is consistent with the standard, which is silent on 
> specifying argument passing mechanisms, so it should result in code 
> that is as portable as possible.  This idea of making your code 
> bulletproof to all possible argument passing methods needs to be 
> extended and/or modified a little bit when some of the newer 
> attributes are considered, such as pointer, target, allocatable, and 
> various INTENTs


That is interesting, as I really didn't know how Fortran passes
arguments to subroutines. I am currently working on a program that
has to pass a lot of large arrays to its subroutines. Some of them
perform calculations based on the values in these arrays, but do not
alter them and some do alter them.
What is the Fortran way of passing an array by reference and
passing an array by value to subroutines?

Cheers, Ralph

0
Reply Ralph 12/2/2009 9:53:29 AM

Ralph Kube <rku000@post.uit.no> wrote:

> When i exchange the call in line 81
> 
> CALL h5dread_f(dset1_id, H5T_NATIVE_DOUBLE, bufnew, data_dims, error)
> 
> with
> 
> CALL h5dread_f(dset1_id, H5T_NATIVE_DOUBLE, bufnew, (/64,64/), error)
> 
> i get a compiler error:
> 
> selectele2.f90(81): error #6285: There is no matching specific 
> subroutine for this generic subroutine call.   [H5DREAD_F]
>        CALL h5dread_f(dset1_id, H5T_NATIVE_DOUBLE, bufnew, (/64,64/), error)
> -----------^
> compilation aborted for selectele2.f90 (code 1)

I'm missing pieces to tell for sure, but this is probably enough to make
at least a decent guess. In particular, let's look at what is different
between those two calls. You focussed on the fact that one uses a
constant where the other uses a variable, but that's not the only
difference, and I doubt it is the important one.

You declare data_dims as

>        INTEGER(HSIZE_T), DIMENSION(2) :: data_dims

Thus it is an integer array of kind hsize_t. On the other hand, (/64,
64/) is an integer array of default kind. I don't know precisely what
value hsize_t has, but I'd venture a guess that it is not the kind value
for default integer.

Generic resolution is not affected by whether the actual argument is a
variable or a constant. But it *IS* affected by the kind. The three key
properties for generic resolution are type, kind, and rank (often
abreviated as TKR). You have a match for the type (integer), and rank
(1), but probably nor for the kind.

You could probably use (/64_hsize_t, 64_hsize_t/) if you really wanted,
but I personally think that awkward. There are a bunch of other
alternatives. Your variable would be one. If you want to keep it as a
constant, you could use a named constant (aka parameter) as in

  integer(hsize_t), parameter :: data_dims(2) = (/64, 64/)

The compiler will convert the kind for you here, just like it probably
converted the kind when you did

>        data_dims(1) = 64
>        data_dims(2) = 64

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam 12/2/2009 10:50:45 AM

Yep, you are right. It runs fine when I pass (/64_hsize_t, 64_hsize_t/) 
to the function, thanks a lot.

Richard Maine wrote:
> Ralph Kube <rku000@post.uit.no> wrote:
> 
>> When i exchange the call in line 81
>>
>> CALL h5dread_f(dset1_id, H5T_NATIVE_DOUBLE, bufnew, data_dims, error)
>>
>> with
>>
>> CALL h5dread_f(dset1_id, H5T_NATIVE_DOUBLE, bufnew, (/64,64/), error)
>>
>> i get a compiler error:
>>
>> selectele2.f90(81): error #6285: There is no matching specific 
>> subroutine for this generic subroutine call.   [H5DREAD_F]
>>        CALL h5dread_f(dset1_id, H5T_NATIVE_DOUBLE, bufnew, (/64,64/), error)
>> -----------^
>> compilation aborted for selectele2.f90 (code 1)
> 
> I'm missing pieces to tell for sure, but this is probably enough to make
> at least a decent guess. In particular, let's look at what is different
> between those two calls. You focussed on the fact that one uses a
> constant where the other uses a variable, but that's not the only
> difference, and I doubt it is the important one.
> 
> You declare data_dims as
> 
>>        INTEGER(HSIZE_T), DIMENSION(2) :: data_dims
> 
> Thus it is an integer array of kind hsize_t. On the other hand, (/64,
> 64/) is an integer array of default kind. I don't know precisely what
> value hsize_t has, but I'd venture a guess that it is not the kind value
> for default integer.
> 
> Generic resolution is not affected by whether the actual argument is a
> variable or a constant. But it *IS* affected by the kind. The three key
> properties for generic resolution are type, kind, and rank (often
> abreviated as TKR). You have a match for the type (integer), and rank
> (1), but probably nor for the kind.
> 
> You could probably use (/64_hsize_t, 64_hsize_t/) if you really wanted,
> but I personally think that awkward. There are a bunch of other
> alternatives. Your variable would be one. If you want to keep it as a
> constant, you could use a named constant (aka parameter) as in
> 
>   integer(hsize_t), parameter :: data_dims(2) = (/64, 64/)
> 
> The compiler will convert the kind for you here, just like it probably
> converted the kind when you did
> 
>>        data_dims(1) = 64
>>        data_dims(2) = 64
> 
0
Reply Ralph 12/2/2009 11:54:39 AM

Ralph Kube wrote:
> Ron Shepard wrote:
>> I agree with this.  You should "imagine" that everything is passed by 
>> address and make sure that your code works that way, and then you 
>> should "imagine" that everything is passed by copy-in/copy-out and 
>> make sure your code works that way too (when appropriate).  And 
>> consider the consequences to your code if arguments are passed through 
>> registers without addresses, and so on.  This results in code that is 
>> consistent with the standard, which is silent on specifying argument 
>> passing mechanisms, so it should result in code that is as portable as 
>> possible.  This idea of making your code bulletproof to all possible 
>> argument passing methods needs to be extended and/or modified a little 
>> bit when some of the newer attributes are considered, such as pointer, 
>> target, allocatable, and various INTENTs
> 
> 
> That is interesting, as I really didn't know how Fortran passes
> arguments to subroutines. I am currently working on a program that
> has to pass a lot of large arrays to its subroutines. Some of them
> perform calculations based on the values in these arrays, but do not
> alter them and some do alter them.
> What is the Fortran way of passing an array by reference and
> passing an array by value to subroutines?
> 
> Cheers, Ralph
> 
There is no Fortran way to force particular calling sequences.
However, since Fortran compilers try to be efficient, they almost
always pass arrays by passing the address of the array and not
doing copy-in/copy-out (or pass by value).  The exception to the
no copy-in/copy-out involves discontigous array sections.  If
you pass a section to a subroutine without an explicit
interface the compiler is (essentially) forced to compact
the array and pass the new temporary address.

However, if you have arrays that aren't intended to be altered
in a subroutine, by all means declare them INTENT(IN).  The
compiler will detect most common errors (and if you put all of
your subroutines in modules, the compiler is likely to detect
all inadvertent modifications).  Similarly, if you declare
things as INTENT(OUT) the compiler is likely to detect
passing a constant or expression to the subroutine.

There is no way to get all of the "features" of pass by
reference.  Given something like
        a = 47
        call xxx(a,a)
        print *, a
....
        subroutine xxx(b,c)
        b = 1
        c = b + 1
        end
The results are undefined and the program is NOT standard
conforming.

Dick Hendrickson
0
Reply Dick 12/2/2009 4:50:24 PM

Richard Maine wrote:
> Phillip Helbig---undress to reply <helbig@astro.multiCLOTHESvax.de>
> wrote:
> 
>> In article <7nlfreF3m6cahU1@mid.individual.net>, Dick Hendrickson
>> <dick.hendrickson@att.net> writes: 
> 
>>> Fortran does NOT pass procedure arguments
>>> by reference.
> 
>> I think that, for most purposes, one can imagine that things are AS IF
>> the compiler passed arguments by reference. 
> 
> Since imagining that quite regularly results in buggy code, I think not.
> Examples abound of bugs from imagining that way. They are a class of
> bugs that sometimes show up only when you turn on optimization. In
> particular, if you imagine that, you will naturally expect to be able to
> change the value of one dummy argument and have that change immediately
> reflected in anything else that dummy argument is associated with;
> that's exactly what a pass by reference would imply. If you aren't
> imagining that, then you aren't really imagining pass by reference.
> 
> I would say it was far more accurate to say that for most purposes, you
> should avoid imagining the implementation details of how arguments are
> passed at all. If your code actually depends on those details, then the
> code is probably buggy anyway. C interop is an exception.
> 
Do you mean that if I use C interop, my code is probably NOT buggy?  ;)

Dick hendrickson
0
Reply Dick 12/2/2009 4:52:13 PM

19 Replies
494 Views

(page loaded in 0.184 seconds)

Similiar Articles:


















7/27/2012 4:54:09 PM


Reply: