I have an R package which uses lots of Fortran subroutines for nested loops of recursive linear algebra computations (depending heavily on BLAS and LAPACK routines). As an interface to Fortran, I use .Fortran
function. I just read Jonathan Callahan's blog post about using .Call
instead of .C
in case of subroutines written in C/C++, and it got me thinking that would it be better to use .Call
interface also when using Fortran subroutines, by writing a simple wrapper in C which then calls the Fortran subroutines?
As said, my Fortran codes are quite simple in a sense that I just play with multidimensional arrays of type double or integer. But I have learned that I must write quite a lot of checks in R side to ensure that everything doesn't crash because of I accidentally forgot to change the storage mode of some matrix to integer or the dimensions of some matrix were changed etc.
Subroutines are written as F90/95.
There might be an advantage if you are working with a large dataset. .Call can be much faster because you are not copying the data each time you call the function. For the case described in this question, there will be no such advantage, because the R 2.15.1 release notes state
.C() and .Fortran() do less copying: arguments which are raw, logical, integer, real or complex vectors and are unnamed are not copied before the call, and (named or not) are not copied after the call. Lists are no longer copied (they are supposed to be used read-only in the C code).
Switching to .Call means you give up the convenience of the .Fortran interface. You'd pass SEXPs into the C code, do any checks/manipulation of the data using the (scary and not well-documented) R API, and then call a Fortran function from C. Anyone else working with your code will have to understand the R API and C/Fortran interop.
The R package dotCall64 could be an interesting alternative. It provides .C64()
which is an enhanced version of the Foreign Function Interface, i.e., .C()
and .Fortran()
.
The interface .C64()
can be used to interface both Fortran and C/C++ code. It
.C()
and .Fortran()
Hence, one can avoid unnecessary copies of read-only arguments while avoiding the .Call()
interface in combination with a C wrapper function.
Some links:
I am one of the authors of dotCall64 and spam.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With