josherrickson/rlemon

runner functions

Closed this issue · 4 comments

My understanding of the runner functions was that the call stack was, e.g.

MaxFlow(..., algorithm = "PreFlow") ->
PreFlowRunner(...) ->
.Call(_rlemon_PreFlowRunner, ...)

However, looking at the code, it looks like we mostly bypass the R Runner:

rlemon/R/maxflow.R

Lines 33 to 37 in dfaf03c

switch(algorithm,
"Preflow" = .Call(
`_rlemon_PreflowRunner`, arcSources, arcTargets,
arcCapacities, sourceNode, destNode, numNodes
),

I'd like to keep using the R runners as a way for users to directly access the LEMON if desired, without any input checks and any other potential cleanups that we do.

Assigning to @arav-agarwal2 for comment in case I'm missing something.

When we stopped exporting the C++ functions, I was under the impression that those R functions are missing from being accessed directly.

Is this not the case?

R's got a variation of public/private objects in packages. A function that is explicitly exported is able to be called directly (MaxFlow()) after loading the package (with library() or require()) or may at any time (even if the package isn't loaded) be called with the double colon notation, e.g. rlemon::MaxFlow().

Alternatively, any object or function that isn't explicitly exported can be called at anytime using the triple colon notation, e.g. rlemon:::PreFlowRunner. It can never be called alone, e.g. PreFlowRunner will always fail.

I like the idea of the package supporting two differences interfaces:

  1. A direct circuit to LEMON in which we guarantee zero pre- and zero post-processing.
  2. A slightly more user-friendly/R-style interface in which we do input checks. (and in the future, may do other pre/post processing).

Typically the way this is done in R is for an exported function foo(), there is a not exported function .foo() which does most of the work. We could use this exact mannerism in this case, or we could stick with the runners being algorithm specific.

Let me think on this.

Ok I've switched it so that exported functions call runners, which in turn use .Call. Its a bit redundant, but I think it'll future-proof us better should we want to tweak input/output anymore.