C# Unmanaged Exports and the R .Call function

Nov 20, 2013 at 2:41 PM
I believe there is another use for your library: writing R Extension libraries in .NET languages invoked with the .Call function in R. Using Giesecke's Unmanaged Exports system for Visual Studio, I am able to create a DLL in C# with unmanaged exported functions that takes IntPtr for arguments. I can then load my DLL with the dyn.load function in R and use the .Call function to invoke my C# code. An R Internals SEXP is passed in through the IntPtr argument, which can be used in the SymbolExpression constructor if that constructor is made public and not internal. I believe this use case is a little different than what R.NET was designed for, but this is a very useful workflow. Please consider supporting this kind of functionality by perhaps exposing the constructor to the SymbolExpression and some addition R.DLL functions in the REngine class for protecting and unprotecting R objects. Then users of the R.NET API can use Unmanaged Exports to write extension libraries for R in .NET languages.
Nov 20, 2013 at 7:25 PM
Edited Nov 20, 2013 at 7:29 PM
Here is an example. I understand the following code may have some memory management issues, but I wanted to provide a clear example of the use scenario I am trying to develop. For the following code to work, I had to make the SymbolicExpression and NumericVector constructors public not internal. DllExport is defined in the RGiesecke.DllExport library, and allows applications to call this function as a standard DLL export. This function can be called from R using .Call after loading the DLL with dyn.load. I'm wondering if others would like this use case supported in R.NET as well, that is R invoking native C# code as an Extension package.
[DllExport("add", CallingConvention = CallingConvention.Cdecl)]
public unsafe static IntPtr add(IntPtr SEXP1, IntPtr SEXP2)
{
  RDotNet.REngine engine = RDotNet.REngine.CreateInstance("r");
  RDotNet.SymbolicExpression sexp1 = new RDotNet.SymbolicExpression(engine, SEXP1);
  RDotNet.SymbolicExpression sexp2 = new RDotNet.SymbolicExpression(engine, SEXP2);
  RDotNet.NumericVector result = new RDotNet.NumericVector(engine, 1);

  if (sexp1.Type == RDotNet.Internals.SymbolicExpressionType.NumericVector
    && sexp2.Type == RDotNet.Internals.SymbolicExpressionType.NumericVector)
  {
    RDotNet.NumericVector vec1 = new RDotNet.NumericVector(engine, SEXP1);
    RDotNet.NumericVector vec2 = new RDotNet.NumericVector(engine, SEXP2);
    int l = Math.Min(vec1.Length, vec2.Length);
    result = new RDotNet.NumericVector(engine, l);

    for(int i = 0; i < l; i++)
      result[i] = vec1[i] + vec2[i];
  }

  return result.DangerousGetHandle();
}
Nov 20, 2013 at 7:29 PM
Hi aengebretson, Very interesting. R.NET is most focused around calling R from .NET. What you are trying to do is call .NET from r, which is handled by rClr. It might be interesting to cross post over there and compare the two approaches.
Nov 20, 2013 at 7:55 PM
Thanks! I was wondering if there was another project already suited for my requirements. I will check it out. Ultimately I believe there must be a lot of overlap and one library could cover both scenarios.
Nov 20, 2013 at 8:00 PM
Definitely agreed there is a lot of overlap. I think the main issue is that with your approach one has to compile a unmanaged front end for the .NET library, which introduces all the cross-platform issues, compiler problems, and dependencies that .NET is trying to avoid. rClr tries to allow arbitrary .NET assemblies to run in R by having R embed mono / .NET, so that there is only one interface from R->CLR->.NET Assemblies, rather than going from R-> Particular assembly interface -> Particular .NET assembly. Though would be curious to see the contrast fleshed out a bit more, as I am not experienced with RGiesecke
Nov 20, 2013 at 8:15 PM
Edited Nov 20, 2013 at 8:15 PM
One thing I don't immediately see in rClr is how to handle R data types in C#, which is what R.NET offers. I'm not sure how rClr does or plans to address that so I still see the need for an API like R.NET to have public constructors that take IntPtr passed from the R environment. As you observed rClr seems to replace my the method of calling .NET assemblies from R, which I am using RGiesecke package. Before I found Giesecke's package I was just using managed/unmanaged C++ to do the same thing, then calling my managed C# code from C++/CLI, which allowed for unmanaged export functions. rClr seems to be trying to bring .NET data types and object references into the R environment. That's a little different than my approach, which is to create R Extensions with C# managed code, and then bring the R data types into C#, referencing R objects in C#. I do not want to reference a DataTable in R, I want to reference a data.frame in C#. All three modes of interfacing seem valid for different use cases.
Developer
Nov 20, 2013 at 10:25 PM
Edited Nov 20, 2013 at 10:25 PM
Hi,

evolvedmicrobe is spot on with the intent of rClr (previous site): accessing arbitrary .NET code with no modification required. Conversely, this means that R data types must be converted to something native to C# (arrays, strings, dictionaries etc.) as R concepts are unknown to the unmodified .NET code. I believe this is very similar to the design philosophy of rJava.

I think I looked at Robert Giesecke's work a couple years ago but your posts are a timely reminder to me BTW.

I think there are ways for you to address your use case. rClr can use R.NET for data type conversions with setRDotNet(TRUE). Prior to a year ago, I had major technical problems with this esp. on Linux so I was unsure this was viable. I am now confident further interop will be written in C# in preference to the C/C++ layer. I needed to make a few changes to R.NET along the lines of what you suggest (public constructors).

I certainly can see use cases for rClr needing to pass data frame to C# and see them as such. Another case is R function "pointers". I believe this is identical to your idea of R extensions, though DllExport declarations need not be present.

I have a mirror of the git repo at rClr on github of rClr on codeplex You are welcome to fork and add/or add use cases at rClr on codeplex as issues or discussions.

Technically, rClr reuses R.NET, but there is not a bidirectional dependency, so the case for merging projects is weak. Nevertheless, there is a clear need for a coordination of promotion/visibility. If you see a case for reuse of RGiesecke's UnmanagedExports in rClr, feel free to make it.