Execute code, set values, and get values in an embedded interpreter.

Share:

Description

These functions define the package's interface to an embedded interpreter. Through these functions, code is executed in the embedded interpreter and data is passed between R and the embedded interpreter. Some of these functions return a function for invoking a function in the interpreter. Others return a reference to the result or attempt to return an R object representing the result. Some functions also provide the ability to clear variables or reclaim memory previously allocated to references. There are convenient shorthand equivalents for many of the functions.

Usage

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
scalaEval(interpreter, snippet, interpolate="")
scalaGet(interpreter, identifier, as.reference=NA)
scalaSet(interpreter, identifier, value, length.one.as.vector="")
scalaDef(interpreter, args, body, interpolate = "", reference=NULL)
scalaCallback(interpreter, argsType, returnType, func, interpolate="")
scalaWrap(interpreter, value)
scalaUnwrap(interpreter, value)
scalaGC(interpreter)
scalaReset(interpreter)
scalap(interpreter, item.name)

interpreter %~% snippet
interpreter %.~% snippet
interpreter %@% snippet

## S3 method for class 'ScalaInterpreter'
interpreter$identifier
## S3 replacement method for class 'ScalaInterpreter'
interpreter$identifier <- value

Arguments

interpreter

An interpreter from an interpreter constructor (i.e. scala).

snippet

A character vector of arbitrary length to be evaluated by the interpreter.

args

A character vector of length one giving the comma-separated Scala arguments for the function to be defined in the interpreter. Use "" for a function which takes no arguments.

body

A character vector of any length giving the body for a function to be defined in the interpreter. The function body can be a multiline character vector of length one.

argsType

A character vector of length one giving the comma-separated Scala types of the function arguments. Use "" for a function which takes no arguments.

returnType

A character vector of length one indicating the return type of the function. This should be equal to ‘XY’, where X is I, D, B, or S and Y is 0, 1, or 2. See the documentation for the RClient class for more details.)

identifier

A character vector of length one containing a valid variable name in the embedded language.

func

An R function to be wrapped by a Scala function. This function is copied and subsequent changes to the function will not be visible to rscala.

value

For scalaWrap, an arbitrary R object. For scalaUnwrap, a result of a call to scalaWrap. For $<- either: i. a vector or matrix of integers, doubles, logicals, or characters, or ii. a reference.

as.reference

A logical vector of length one indicating whether the result of scalaGet should return a reference to the function result or whether these functions should try to interpret the result as a vector or matrix of integer, doubles, logicals, or characters. The default is NA which first tries as.reference=FALSE and, if no conversion is possible, as.reference=TRUE is done.

interpolate

When equal to "" (the default), the default behavior from scalaSettings is used. If equal to TRUE, the interpreter will call strintrplt on the supplied code before running it. If equal to FALSE, the character vector is passed unaltered.

length.one.as.vector

When equal to "" (the default), the default behavior from scalaSettings is used. If equal to TRUE, setting a vector of length one in the interpreter will result in an array of length one. If equal to FALSE, setting a vector of length one results in an atomic value. For example, pi is a vector of length one in R and, when set in an interpreter, would result in an array of doubles of length one if length.one.as.vector is TRUE or a double if length.one.as.vector is FALSE.

reference

This option is meant only for developers of the package itself and not intended for users of the package.

item.name

A character vector of length one containing the name of an object/class for which the ‘scalap’ command should be run.

Details

The convenient shorthand notation interpreter %@% snippet evaluates the expression snippet, whereas interpreter %~% snippet both evaluates the expression snippet and attempts to return a vector or matrix of integers, doubles, logicals, or characters or — if this is not possible — NULL is returned. The convenient shorthand notation interpreter %.~% snippet has the same behavior except it always returns a reference. References may be used later as the value in scalaSet or as an argument to a function returned by scalaDef. Note, however, the memory associated with values returned by %~% and %.~% is never garbage-collected. Likewise, memory allocated in the global environment of the Scala interpreter is never garbage-collected. (See the Scala bug detailed here: https://issues.scala-lang.org/browse/SI-4331.)

Memory associated with the return values by function defined by scalaDef, however, is able to be garbage-collected. Thus, heavy usage of functions defined by scalaDef is encouraged for memory intensive applications. (Use scalaGC to invoke the interpreter's garbage collector.) Further, functions defined by scalaDef have less invocation latency than the equivalent code using %~% and %.~%. The speed difference in invocation is especially noticeable for quick functions.

The convenient shorthand notations interpreter$identifier and interpreter$identifier <- value make it easy to get and set variables in the interpreter. Note, however, that def is a reserved word in Scala and, as such, is treated as a special case: interpreter$def(args,body) is equivalent to scalaDef(interpreter,args,body). See the examples below.

Value

scalaEval, scalaSet, scalaGC, and scalaReset silently return NULL.

scalaGet returns a reference to the result if as.reference is TRUE. If as.reference is FALSE, the function tries to convert the result to a vector or matrix of integers, doubles, logicals, or characters. If a conversion is not possible, NULL is silently returned.

scalaDef returns an R function that calls the corresponding function defined by the args and body. In addition to the arguments specified in args, the resulting function also has named arguments as.reference and gc. The first two have the same behavior as described above. The gc argument specifies whether the interpreter's garbage collector should be run to free references. The default is FALSE for performance reasons. Instead of setting gc to TRUE, it is recommended that the function scalaGC be periodically run if many references from a function returned by scalaDef are generated.

Author(s)

David B. Dahl dahl@stat.byu.edu

See Also

scala, scalaSettings, strintrplt

Examples

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
## Not run: 
# Get an instance of a Scala interpreter and see the default settings
s <- scala()
scalaSettings(s)

# Demonstrate convenient notation and string interpolation
stringFromScala <- s %~% '"Hello @{Sys.getenv("USER")} from @{R.Version()$nickname}" + "!"*10'
stringFromScala

# Set and get variables
s$rPi <- pi
s$rPi

# Make vectors of length one be set as arrays
scalaSettings(s,length.one.as.vector=TRUE)

# Unlike above, now 'pi' is set as an array of length one
s$rPi <- pi
scalaGet(s,"rPi")
scalaGet(s,"rPi",as.reference=TRUE)              # Get the result as a reference
scalaSet(s,"rPi",pi,length.one.as.vector=FALSE)  # Override current global setting
scalaSettings(s,length.one.as.vector=FALSE)      # Put it back to the default

# Convenient notation
a1 <- s %~%  "rPi/2"   # As an R value
a2 <- s %.~% "rPi/2"   # As a reference

# References can be set
s$foo <- a2

# Get a reference to an R object
myList <- list(a=2, b=matrix(1:8,nrow=2))
wrappedList <- scalaWrap(s,myList)
identical(myList,scalaUnwrap(s,wrappedList))
s$.myList <- myList
identical(myList,s$myList)

# Instantiate an object
seed <- 2349234L
scalap(s,'scala.util.Random')
rng <- s$do('scala.util.Random')$new(seed)  # Scala equivalent: new scala.util.Random(seed)

# Call method of a reference
system.time(rng$nextInt(100L))   # Scala equivalent: rng.nextInt(100)
system.time(rng$nextInt(100L))   # Notice it runs much faster after the first time

# Call method of companion object and call methods of a reference
# Scala equivalent: (scala.math.BigInt('777',8) - 500).intValue
s$do('scala.math.BigInt')$apply('777',8L)$'-'(500L)$intValue()

# Example showing 'scalaCallback' functionality
f1 <- function(x) 2*x
f2 <- s$callback('Double','D0',f1)
s 

# Longer example showing that 'scalaDef' is more flexible and faster than '%~%'
scalaSet(s,"rng",rng)
drawGaussian <- scalaDef(s,'mean: Double, sd: Double','mean+sd*rng.nextDouble')
drawGaussian(3,0.1)
n.draws <- 100
system.time({
  draws <- s %~% '
    val result = new Array[Double](@{n.draws})
    result(0) = rng.nextGaussian
    for ( i <- 1 until @{n.draws} ) {
      result(i) = 0.5*result(i-1) + rng.nextGaussian
    }
    result
  '
  acf(draws,plot=FALSE)
})
sampler <- s$def('nDraws: Int, rho: Double','
  val result = new Array[Double](nDraws)
  result(0) = rng.nextGaussian
  for ( i <- 1 until nDraws ) {
    result(i) = rho*result(i-1) + rng.nextGaussian
  }
  result
')
system.time(acf(sampler(n.draws,0.5),plot=FALSE))
system.time(acf(sampler(n.draws,0.9),plot=FALSE))

## End(Not run)