Saturday, July 31, 2021

SwiftR Switcheroo: Calling [Compiled] Swift from R!

I’ve been on a Swift + R bender for some time now, however have been envious of the pure macOS/iOS (et al) of us who get to make use of Apple’s severely ++good machine studying libraries, that are much more sturdy on the brand new M1 {hardware} (it’s cool having {hardware} parts devoted to bettering the efficiency of constructed fashions).

Certain, it’s fairly easy to make a command-line utility that may take knowledge enter, run them via fashions, then haul the info again into R, however I figured it was about time that Swift obtained the “Rust” and “Go” remedy when it comes to letting R name compiled Swift code straight. Fortunately, none of this entails utilizing Xcode because it’s one of many world’s worst IDEs.

To play alongside at dwelling you’ll want macOS and at the very least the command line instruments put in (I don’t assume this requires a full Xcode set up, however y’all can let me know if it does within the feedback). Should you can enter swiftc at a terminal immediate and get again <unknown>:0: error: no enter information you then’re good-to-go.

Good day, Swift!

To maintain this submit quick (since I’ll be including this complete idea to the SwiftR tome), we’ll be super-focused and simply construct a shared library we will dynamically load into R. That library may have one operate which will probably be to allow us to say hi there to the planet with a custom-made greeting.

Make a brand new listing for this effort (I known as mine greetings) and create a greetings.swift file with the next contents:

NOTE: Please substitute an actual @ signal for the @ used right here. One of many extensions that auto-converts @- issues to Twitter hyperlinks is busted and turns all of them to Twitter hyperlinks.

All this code can also be on this gist.

@_cdecl("greetings_from")
public func greetings_from(_ who: SEXP) -> SEXP {
  print("Greetings, 🌎, it is (String(cString: R_CHAR(STRING_ELT(who, 0))))!")
  return(R_NilValue)
}

Earlier than I clarify what’s happening there, additionally create a geetings.h file with the next contents:

#outline USE_RINTERNALS

#embrace <R.h>
#embrace <Rinternals.h>

const char* R_CHAR(SEXP x);

Within the Swift file, there’s a single operate that takes an R SEXP and converts it right into a Swift String which is then routed to stdout (not a “nice” R idiom, however benign sufficient for an intro instance). Swift capabilities aren’t C capabilities and on their very own don’t adhere to C calling conventions. Sadly R’s skill to work with dynamic library code requires such a contract to be in place. Fortunately, the Swift Language Overlords offered us with the power to instruct the compiler to create library code that may drive the calling conventions to be C-like (that’s what the @cdecl is for).

We’re utilizing SEXP, some R C-interface capabilities, and even the C model of NULL within the Swift code, however we haven’t finished something within the Swift file to inform Swift concerning the existence of those parts. That’s what the C header file is for (I added the R_CHAR declaration since advanced C macros don’t work in Swift).

Now, all we have to do is be sure that the compiler is aware of concerning the header file (which is a “bridge” between C and Swift), the place the R framework is, and that we wish to generate a library vs a binary executable file as we compile the code. Be sure you’re in the identical listing as each the .swift and .h file and execute the next at a terminal immediate:

swiftc 
  -I /Library/Frameworks/R.framework/Headers  # the place the R headers are
  -F/Library/Frameworks                       # the place the R.framework lives
  -framework R                                # we wish to hyperlink in opposition to the R framework
  -import-objc-header greetings.h             # that is our bridging header which is able to make R C issues obtainable to Swift
  -emit-library                               # we would like a library, not an exe
  greetings.swift                              # our file!

If all goes properly, you need to have a libgreetings.dylib shared library in that listing.

Now, fireplace up a R console session in that listing and do:

greetings_lib <- dyn.load("libgreetings.dylib")

If there are not any errors, the shared library has been loaded into your R session and we will use the operate we simply made! Let’s wrap it in an R operate so we’re not always typing .Name(…):

greetings_from <- operate(who = "me") {
  invisible(.Name("greetings_from", as.character(who[1])))
}

I additionally took the chance to ensure we’re sending a length-1 character vector to the C/Swift operate.

Now, say hi there!

greetings_from("hrbrmstr")

And you need to see:

Greetings, 🌎, it is hrbrmstr!

FIN

We’ll cease there for now, however hopefully this small introduction has proven how easy it may be to bridge Swift & R within the different path.

I’ll have one other submit that exhibits easy methods to lengthen this toy instance to make use of one among Apple’s pure language processing libraries, and should even do yet another on easy methods to put all this right into a package deal earlier than I shunt all the person posts into a couple of e book chapters.

*** This can be a Safety Bloggers Community syndicated weblog from rud.is authored by hrbrmstr. Learn the unique submit at: https://rud.is/b/2021/01/23/swiftr-switcheroo-calling-compiled-swift-from-r/

Latest news

Related news

LEAVE A REPLY

Please enter your comment!
Please enter your name here