Custom Conversion
RCall supports an API for implicitly converting between R and Julia objects by means of rcopy
and RObject
.
To illustrate the idea, we consider the following Julia type
type Foo
x::Float64
y::String
end
foo = Foo(1.0, "hello")
Julia to R direction
The function RCall.sexp
has to be overwritten to allow Julia to R conversion. sexp
function takes a julia object and returns an SEXP object (pointer to [Sxp
]).
import RCall.sexp
function sexp(f::Foo)
r = protect(sexp(Dict(:x => f.x, :y => f.y)))
setclass!(r, sexp("Bar"))
unprotect(1)
r
end
roo = RObject(foo)
nothing # hide
Remark: RCall.protect
and RCall.unprotect
should be used to protect SEXP from being garbage collected.
R to Julia direction
The function rcopy
and rcopytype
are responsible for conversions of this direction. First we define an explicit converter for VecSxp (SEXP for list)
import RCall.rcopy
function rcopy(::Type{Foo}, s::Ptr{VecSxp})
Foo(rcopy(Float64, s[:x]), rcopy(String, s[:y]))
end
rcopy (generic function with 109 methods)
The convert
function will dispatch the corresponding rcopy
function when it is found.
rcopy(Foo, roo)
convert(Foo, roo) # calls `rcopy`
Foo(roo)
nothing # hide
To allow the automatic conversion via rcopy(roo)
, the R class Bar
has to be registered.
import RCall: RClass, rcopytype
rcopytype(::Type{RClass{:Bar}}, s::Ptr{VecSxp}) = Foo
boo = rcopy(roo)
nothing # hide
Using @rput and @rget is seamless
boo.x = 2.0
@rput boo
R"""
boo["x"]
"""
R"""
boo["x"] = 3.0
"""
@rget boo
boo.x
Nested conversion
l = R"list(boo = boo, roo = $roo)"
rcopy(l)