Hi,
I think there are two easy ways to fix this. The first is to use a `switch` to call the intended function, this should not be a problem since there are a small number of print functions in **mixR** ```R print.mixfitEM <- function (x, digits = getOption("digits"), ...) { switch(x$family, gamma = printgamma (x, digits), lnorm = printlnorm (x, digits), normal = printnormal (x, digits), weibull = printweibull(x, digits), stop(gettextf("invalid '%s' value", "x$family", domain = "R"))) invisible(x) } environment(print.mixfitEM) <- getNamespace("mixR") print.mixfitEM <- compiler::cmpfun(print.mixfitEM) ``` This is nice because 'x' is no longer evaluated twice (you could try this yourself with something like `mixR:::print.mixfitEM(writeLines("testing"))`, you'll see the output twice, once for `x$family` and a second for evaluating `match.call()` expression), it follows standard evaluation, and 'x' is returned invisibly at the end, like most other `print` methods. If you really wanted to continue using `eval`, you could instead do something like ```R print.mixfitEM <- function (x, digits = getOption("digits"), ...) { expr <- quote(printfunction(x, digits)) expr[[1L]] <- as.symbol(paste0("print", x$family)) eval(expr) invisible(x) } environment(print.mixfitEM) <- getNamespace("mixR") print.mixfitEM <- compiler::cmpfun(print.mixfitEM) ``` This also solves the same issues, but it's ugly and slower. At least for now, I would copy one of the functions above into the site-wide startup profile file or your user profile, along with ```R utils::assignInNamespace("print.mixfitEM", print.mixfitEM, "mixR") ``` This does have the unfortunate side effect of loading **mixR** every time an R session is launched, but you could also put it inside another function like: ```R fix.mixR.print.mixfitEM <- function () { print.mixfitEM <- function(x, digits = getOption("digits"), ...) { switch(x$family, gamma = printgamma (x, digits), lnorm = printlnorm (x, digits), normal = printnormal (x, digits), weibull = printweibull(x, digits), stop(gettextf("invalid '%s' value", "x$family", domain = "R"))) invisible(x) } environment(print.mixfitEM) <- getNamespace("mixR") print.mixfitEM <- compiler::cmpfun(print.mixfitEM) utils::assignInNamespace("print.mixfitEM", print.mixfitEM, "mixR") } ``` which you would then call in your scripts before using **mixR**. I hope this helps! On Thu, May 25, 2023 at 10:19 AM Sarah Goslee <sarah.gos...@gmail.com> wrote: > Hi, > > I ran into a problem with S3 method dispatch and scoping while trying > to use functions from the mixR package within my own functions. I know > enough to find the problem (I think!), but not enough to fix it > myself. The problem isn't really a package-specific problem, so I'm > starting here, and will file an issue with the maintainer once I have > a solution. > > Detailed explanation below, but briefly, the S3 methods in this > package use match.call() and then eval() to select the correct > internal method. This works fine from the command line, but if the > method is called from within another function, the use of > environment() within eval() means that the objects passed to the > wrapper function are no longer visible within the eval() call. > > I have a two-part question: > A. How do I get around this right now? > B. What would the correct approach be for the package authors? > > library(mixR) > > # first example from ?mixfit > ## fitting the normal mixture models > set.seed(103) > x <- rmixnormal(200, c(0.3, 0.7), c(2, 5), c(1, 1)) > data <- bin(x, seq(-1, 8, 0.25)) > fit1 <- mixfit(x, ncomp = 2) # raw data > rm(x, data) > ### > > # simple function > funworks <- function(x) { > print(x) > } > > ### > > # almost identical simple function > funfails <- function(thisx) { > print(thisx) > } > > ### > > funworks(fit1) > funfails(fit1) > > ####### > > The explanation as I understand it... > > print called on this object gets passed to print.mixfitEM(), which is: > > > function (x, digits = getOption("digits"), ...) > { > family <- x$family > mc <- match.call() > mc$digits <- digits > fun.name <- paste0("print", family) > mc[[1]] <- as.name(fun.name) > eval(mc, environment()) > } > > > Working through the calls, when eval() is called from within funfails(), > mc is > printnormal(x = thisx, digits = 7) > and the calling environment does not contain thisx. > > In funworks(), it's > printnormal(x = x, digits = 7) > > and x is found. > > So, I can get around the problem by naming my argument x, as in > funworks(), but that's unsatisfying. Is there something else I can do > to get my functions to work? > > And what's the correct way to do what print.mixfitEM() is doing, so > that it works regardless? I poked around for a while, but didn't find > a clear (to me!) answer. > > Thanks, > Sarah > > -- > Sarah Goslee (she/her) > http://www.numberwright.com > > ______________________________________________ > R-help@r-project.org mailing list -- To UNSUBSCRIBE and more, see > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide > http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. > [[alternative HTML version deleted]] ______________________________________________ R-help@r-project.org mailing list -- To UNSUBSCRIBE and more, see https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.