simplefortran - demo package for calling C code with .C()

July 4, 2020 · View on GitHub

simplefortran is a small demo package showing how Fortran code could be included in a package and called with .Fortran()

This is one of a series of small demo packages for
calling other languages from R:

Rough comparison of .C(), .Call(), {Rcpp} (and .Fortran())

.C().Call()Rcpp
OverviewNo real understanding of R objectsNeed to understand SEXP macros & internalsC++ classes hide the complexity of the SEXP internals
What code?Basic C code. Numeric calcs.Complex C code. Can manipulate R objects from CComplex C and C++ code involving numerics and R objects
ProsSimple to understand and useSimple. No unnecessary copying.Great documentation. Wrapping of R objects very intuitive.
ConsToo simple for most interesting thingsNeed to understand SEXP & R internals
ConsPerforms copying of data to call functions
Demo R package{simplec}{simplecall}{simplercpp}
Compiled size17 kB17 kB92 kB (stripping can bring this down: see issue1)
.Fortran()
OverviewNo real understanding of R objects
What code?Basic Fortran code. Numeric calcs.
ProsSimple to understand and use
ConsToo simple for most interesting things
ConsPerforms copying of data to call functions
ConsNeed to know Fortran!
Demo R package{simplefortran}
Compiled size17 kB

Installation

You can install from GitHub with:

# install.package('remotes')
remotes::install_github('coolbutuseless/simplefortran)

What’s in the box?

Package contains 2 Fortran functions, and 2 functions in R which call the Fortran functions using .Fortran().

Fortran functionR function
subroutine add_(x, y, answer)add_Fortran(x, y)
subroutine mul_(x, y, answer)mul_Fortran(x, y)

What’s in the R functions?

  • A call using .Fortran()
  • First argument is the Fortran function name e.g. add_
  • x and y arguments are passed through from the R function
  • the third argument to the function is space in which to store the result i.e. numeric(1)
  • .Fortran() returns as many arguments as you gave it originally
  • We only want to return the actual result, which is the third argument, hence [[3]]
  • @useDynLib [packagename] [Fortran function name] is used to generate the NAMESPACE entry useDynLib(simplefortran, add_)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#' Add two numbers
#'
#' @param x,y numbers to add
#'
#' @useDynLib simplefortran add_
#' @export
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
add_Fortran <- function(x, y) {
  .Fortran(add_, x, y, numeric(1))[[3]]
}

What’s in the Fortran functions?

  • Actual result must be stored in one of the arguments
        subroutine add_(x, y, answer)
c
c add 2 numbers
c
        double precision x, y, answer

        answer = x + y

        end

How do R variables map to Fortran variables?

RFortran
logicalINTEGER
integerINTEGER
doubleDOUBLE PRECISION
complexDOUBLE COMPLEX
characterCHARACTER(255)
raw(none)

What does the Fortran function look like in R?

  • An object of class NativeSymbolInfo
  • Holds an externalptr to the loaded function
simplefortran:::add_
#> $name
#> [1] "add_"
#> 
#> $address
#> <pointer: 0x1055e3ec0>
#> attr(,"class")
#> [1] "NativeSymbol"
#> 
#> $dll
#> NULL
#> 
#> attr(,"class")
#> [1] "NativeSymbolInfo"

Resources

Acknowledgements

  • R Core for developing and maintaining such a wonderful language.
  • CRAN maintainers, for patiently shepherding packages onto CRAN and maintaining the repository