Re: [Rd] Error in help files connection
On 25/01/2015 1:58 PM, Axel Urbiz wrote: > Hello, > > I'm building a package on Mac OS. The build/check/install goes all ok. > Also, the package gets loaded properly with library(my_package). > > However, when I call the help file for a given function in the package -- > i.e., "?my_function", I get the following error: > > Error in gzfile(file, "rb") : cannot open the connection > > I've search for this issue, but did not find anything that could help in my > case. > You'll need to make your package available if you want someone else to help. If you want to do it yourself, use options(error=recover) to find out what file R was trying to open, likely something like /Library/Frameworks/R.framework/Resources/library/*/Meta/package.rds and then work out why R was unable to open it. Duncan Murdoch __ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
Re: [Rd] names function for environments?
> Michael Lawrence > on Tue, 27 Jan 2015 07:59:59 -0800 writes: > Since the contract of ls() is to sort, there is nothing wrong with > programmers depending on it. And there are many functions that could be > made 60X faster, but is it worth it? But I did notice that > as.list.environment has a sorted=FALSE argument already, so I guess > identical(names(x), names(as.list(x))) could be made to be TRUE, assuming > the order is at least persistent, if undefined, so that is a nice property. > I guess I'm OK it with. As we ended only hearing "pro"s and no real "con"s, I've committed (a corrected version of) the code now. The above identity is not true in generality though, but identical(names(x), names(as.list(x, all.names=TRUE))) is now for an environment 'x'. One could think to change the default of 'all.names' in as.list.environment(.) from FALSE to TRUE, but that may break code in subtle places and I don't think we should go there. Martin > On Tue, Jan 27, 2015 at 7:44 AM, Peter Haverty > wrote: >> I think that the "sorted" and "all.names" arguments are really only >> appropriate for pretty printing to the screen. I think it is a bit >> unfortunate that environments have a names accessor that is 60X slower >> than all the other types. This is likely due to the history of >> environments, which were originally just for behind-the-scenes tasks. >> >> Now that users can use environments as hashes, we really need >> something like a "keys" function. We don't want programmers depending >> on the sorted-ness, as Martin mentioned. Also, I think it helps users >> when objects share as many of the key API functions as possible. >> "names" is natural. "ls" was certainly confusing for me when I >> started. Having to supply two additional arguments to get the desired >> output doesn't help there. Think of all the perl programmers >> struggling to switch to R. Let's help them out. >> Pete >> >> >> Peter M. Haverty, Ph.D. >> Genentech, Inc. >> phave...@gene.com >> >> >> On Tue, Jan 27, 2015 at 7:26 AM, Michael Lawrence >> wrote: >> > I think ls(, sort=FALSE) would be more explicit and thus clearer. There >> is >> > much precedent for having arguments that request less work to be done >> e.g. >> > unlist(use.names=FALSE). Yes, the extra typing is a bit painful, but >> there >> > is no intuitive reason why names() would be unsorted, while ls() would be >> > sorted. While it is tempting to use an existing function for this, the >> word >> > "names" is somewhat loaded. For example, one might expect >> > identical(names(env), names(as.list(env))) to be TRUE. I see no problem >> with >> > making names() a simple alias of ls(), as long as the behavior is the >> same. >> > Maybe a different name would be less "loaded" and imply lack of order, >> > something like keySet(). But do we really need this? >> > >> > >> > >> > >> > >> > >> > On Tue, Jan 27, 2015 at 7:11 AM, Martin Maechler >> > wrote: >> >> >> >> > Peter Haverty >> >> > on Sun, 25 Jan 2015 12:21:04 -0800 writes: >> >> >> >> > Hi all, >> >> > The "ls" function wears two hats. It allows users to inspect an >> >> > environment interactively and also serves deeper in code as the >> >> > accessor for an environment's names/keys. I propose that we >> separate >> >> > these two conflicting goals, keeping ls for interactive use and >> >> adding >> >> > names for a quick listing of the hash keys. This involves adding >> two >> >> > lines to do_names in attrib.c. >> >> >> >> > The 'ls' function and its 'objects' synonym appear very frequently >> >> in >> >> > performance-critical code like base/R/namespace.R and throughout >> the >> >> > methods package. These functions are currently among the major >> >> > contributors to execution time in package loading. >> >> >> >> > This two-line addition to attrib.c gives a significant speedup for >> >> > listing an environment's names/keys (2-60X depending on the >> 'sorted' >> >> > argument). It also simplifies the environment API by making it >> more >> >> > like the other basic types. We already have $ and [[ after all. >> >> >> >> > Rather than sprinkling sorted=FALSE throughout the methods and >> base >> >> > code, let's use names. >> >> >> >> as for list()s and other (generalized) vectors. >> >> >> >> This sounds appealing at first, and I have heard/seen others propose >> >> it. I see one good reason *not* to allow it (and you mention the >> >> reason by mentioning 'sorted') : >> >> >> >> The contents of
Re: [Rd] [Q] Get formal arguments of my implemented S4 method
On Jan 28, 2015, at 6:37 PM, Michael Lawrence wrote: > At this point I would just due: > > formals(body(method)[[2L]]) > > At some point we need to figure out what to do with this .local() confusion. Agreed, definitely. The current hack is to avoid re-matching arguments on method dispatch, so a fix would need to be fairly deep in the implementation. But I don't think the expression above is quite right. body(method)[[2L]] is the assignment. You need to evaluate the rhs. Here is a function that does the same sort of thing, and returns the standard formals for the generic if this method does not have nonstandard arguments. We should probably add a version of this function for 3.3.0, so user code doesn't have hacks around the current hack. methodFormals <- function(f, signature = character()) { fdef <- getGeneric(f) method <- selectMethod(fdef, signature) genFormals <- base::formals(fdef) b <- body(method) if(is(b, "{") && is(b[[2]], "<-") && identical(b[[2]][[2]], as.name(".local"))) { local <- eval(b[[2]][[3]]) if(is.function(local)) return(formals(local)) warning("Expected a .local assignment to be a function. Corrupted method?") } genFormals } > > > > > On Wed, Jan 28, 2015 at 10:07 AM, Roebuck,Paul L > wrote: > >> I'm attempting to reflect the information for use with corresponding >> fields in GUI (in a different package), to provide default values, >> argname as key for UI label lookups, etc. >> >> So I want something much more like the formals of the implementation: >> >> { >>"object", >>"method": c("median", "vs", "tukey"), >>"calc.medians": TRUE, >>"sweep.cols": calc.medians, >>"recalc.after.sweep": sweep.cols, >>"�" >> } >> >> not those of the generic: >> >> { >>"object", >>"�" >> } >> >> >> From: Michael Lawrence >> Date: Wednesday, January 28, 2015 11:28 AM >> To: "Roebuck,Paul L" >> Cc: R-devel >> Subject: Re: [Rd] [Q] Get formal arguments of my implemented S4 method >> >> >> Would you please clarify your exact use case? >> >> >> Thanks, >> Michael >> >> >> On Wed, Jan 28, 2015 at 9:02 AM, Roebuck,Paul L >> wrote: >> >> Interrogating some (of my own) code in another package. >> >>> norm.meth <- getMethod("normalize", "MatrixLike") >>> message("str(norm.meth)") >>> str(norm.meth) >> >>> message("show(norm.meth@.Data)") >>> show(norm.meth@.Data) >> >> >> Last show() displays this: >> >> function (object, ...) >> { >>.local <- function (object, method = c("median", "vs", "tukey"), >>calc.medians = TRUE, sweep.cols = calc.medians, >>recalc.after.sweep = sweep.cols, ...) >>{ >>.do_normalize(object, >>method = match.arg(method), >>calc.medians = calc.medians, >>sweep.cols = sweep.cols, >>recalc.after.sweep = recalc.after.sweep, >>...) >>} >>.local(object, ...) >> } >> >> >> Desire to be able to access formals() for the .local() function definition, >> not the generic one. Have seen information desired available via "defined" >> slot of returned 'MethodDefinition' object, but not using the code below. >> >> >> >> >> >> library(methods) >> >> if (!isGeneric("normalize")) { >>## Other packages also define this generic... >>setGeneric("normalize", >> function(object, ...) standardGeneric("normalize")) >> } >> >> setClassUnion("MatrixLike", c("matrix", "data.frame")) >> >> .do_normalize <- function(concs, >> method, >> calc.medians, >> sweep.cols, >> recalc.after.sweep, >> ...) { >>message("internal routine called!") >>NULL >> } >> >> setMethod("normalize", signature(object="MatrixLike"), >> function(object, >> method=c("median", "vs", "tukey"), >> calc.medians=TRUE, >> sweep.cols=calc.medians, >> recalc.after.sweep=sweep.cols, >> ...) { >> >>.do_normalize <- function(object, >>method=match.arg(method), >>calc.medians=calc.medians, >>sweep.cols=sweep.cols, >>recalc.after.sweep=recalc.after.sweep, >>...) >> } >> >> __ >> R-devel@r-project.org mailing list >> https://stat.ethz.ch/mailman/listinfo/r-devel >> >> >> >> >> >> > > [[alternative HTML version deleted]] > > __ > R-devel@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel [[alternative HTML version deleted]] __ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinf
Re: [Rd] names function for environments?
On Thu, Jan 29, 2015 at 5:51 AM, Martin Maechler < maech...@lynne.stat.math.ethz.ch> wrote: > > Michael Lawrence > > on Tue, 27 Jan 2015 07:59:59 -0800 writes: > > > Since the contract of ls() is to sort, there is nothing wrong with > > programmers depending on it. And there are many functions that could > be > > made 60X faster, but is it worth it? But I did notice that > > as.list.environment has a sorted=FALSE argument already, so I guess > > identical(names(x), names(as.list(x))) could be made to be TRUE, > assuming > > the order is at least persistent, if undefined, so that is a nice > property. > > I guess I'm OK it with. > > As we ended only hearing "pro"s and no real "con"s, > I've committed (a corrected version of) the code now. > > The above identity is not true in generality though, but > > identical(names(x), names(as.list(x, all.names=TRUE))) > > is now for an environment 'x'. > > One could think to change the default of 'all.names' in > as.list.environment(.) from FALSE to TRUE, > but that may break code in subtle places and I don't think we > should go there. > > Yea, but it is super weird that as.list() filters elements out of the environment during coercion. I think I'm going to look through the uses of ls() inside of the core packages, because I suspect that is usually not necessary to extract the keys, and there is a cleaner (and probably faster) way to achieve the same result. > Martin > > > > On Tue, Jan 27, 2015 at 7:44 AM, Peter Haverty < > haverty.pe...@gene.com> > > wrote: > > >> I think that the "sorted" and "all.names" arguments are really only > >> appropriate for pretty printing to the screen. I think it is a bit > >> unfortunate that environments have a names accessor that is 60X > slower > >> than all the other types. This is likely due to the history of > >> environments, which were originally just for behind-the-scenes > tasks. > >> > >> Now that users can use environments as hashes, we really need > >> something like a "keys" function. We don't want programmers > depending > >> on the sorted-ness, as Martin mentioned. Also, I think it helps > users > >> when objects share as many of the key API functions as possible. > >> "names" is natural. "ls" was certainly confusing for me when I > >> started. Having to supply two additional arguments to get the > desired > >> output doesn't help there. Think of all the perl programmers > >> struggling to switch to R. Let's help them out. > >> Pete > >> > >> > >> Peter M. Haverty, Ph.D. > >> Genentech, Inc. > >> phave...@gene.com > >> > >> > >> On Tue, Jan 27, 2015 at 7:26 AM, Michael Lawrence > >> wrote: > >> > I think ls(, sort=FALSE) would be more explicit and thus clearer. > There > >> is > >> > much precedent for having arguments that request less work to be > done > >> e.g. > >> > unlist(use.names=FALSE). Yes, the extra typing is a bit painful, > but > >> there > >> > is no intuitive reason why names() would be unsorted, while ls() > would be > >> > sorted. While it is tempting to use an existing function for > this, the > >> word > >> > "names" is somewhat loaded. For example, one might expect > >> > identical(names(env), names(as.list(env))) to be TRUE. I see no > problem > >> with > >> > making names() a simple alias of ls(), as long as the behavior is > the > >> same. > >> > Maybe a different name would be less "loaded" and imply lack of > order, > >> > something like keySet(). But do we really need this? > >> > > >> > > >> > > >> > > >> > > >> > > >> > On Tue, Jan 27, 2015 at 7:11 AM, Martin Maechler > >> > wrote: > >> >> > >> >> > Peter Haverty > >> >> > on Sun, 25 Jan 2015 12:21:04 -0800 writes: > >> >> > >> >> > Hi all, > >> >> > The "ls" function wears two hats. It allows users to > inspect an > >> >> > environment interactively and also serves deeper in code > as the > >> >> > accessor for an environment's names/keys. I propose that we > >> separate > >> >> > these two conflicting goals, keeping ls for interactive > use and > >> >> adding > >> >> > names for a quick listing of the hash keys. This involves > adding > >> two > >> >> > lines to do_names in attrib.c. > >> >> > >> >> > The 'ls' function and its 'objects' synonym appear very > frequently > >> >> in > >> >> > performance-critical code like base/R/namespace.R and > throughout > >> the > >> >> > methods package. These functions are currently among the > major > >> >> > contributors to execution time in package loading. > >> >> > >> >> > This two-line addition to attrib.c gives a significant > speedup for > >> >> > listing an env
Re: [Rd] [Q] Get formal arguments of my implemented S4 method
On Thu, Jan 29, 2015 at 5:57 AM, John Chambers wrote: > > On Jan 28, 2015, at 6:37 PM, Michael Lawrence > wrote: > > At this point I would just due: > > formals(body(method)[[2L]]) > > At some point we need to figure out what to do with this .local() > confusion. > > > Agreed, definitely. The current hack is to avoid re-matching arguments on > method dispatch, so a fix would need to be fairly deep in the > implementation. > > But I don't think the expression above is quite right. body(method)[[2L]] > is the assignment. You need to evaluate the rhs. > > Sorry, thanks for the catch. > Here is a function that does the same sort of thing, and returns the > standard formals for the generic if this method does not have nonstandard > arguments. We should probably add a version of this function for 3.3.0, so > user code doesn't have hacks around the current hack. > > methodFormals <- function(f, signature = character()) { > fdef <- getGeneric(f) > method <- selectMethod(fdef, signature) > genFormals <- base::formals(fdef) > b <- body(method) > if(is(b, "{") && is(b[[2]], "<-") && identical(b[[2]][[2]], > as.name(".local"))) > { > local <- eval(b[[2]][[3]]) > if(is.function(local)) > return(formals(local)) > warning("Expected a .local assignment to be a function. Corrupted > method?") > } > genFormals > } > > Yea, I had thought about having that, or a more general getMethodFunction() on which formals() could be called. I held back though, because I thought it might be best to address the .local issue, instead of introducing additional API components that would otherwise be unnecessary. > > > > On Wed, Jan 28, 2015 at 10:07 AM, Roebuck,Paul L > > wrote: > > I'm attempting to reflect the information for use with corresponding > fields in GUI (in a different package), to provide default values, > argname as key for UI label lookups, etc. > > So I want something much more like the formals of the implementation: > > { >"object", >"method": c("median", "vs", "tukey"), >"calc.medians": TRUE, >"sweep.cols": calc.medians, >"recalc.after.sweep": sweep.cols, >"Š" > } > > not those of the generic: > > { >"object", >"Š" > } > > > From: Michael Lawrence > Date: Wednesday, January 28, 2015 11:28 AM > To: "Roebuck,Paul L" > Cc: R-devel > Subject: Re: [Rd] [Q] Get formal arguments of my implemented S4 method > > > Would you please clarify your exact use case? > > > Thanks, > Michael > > > On Wed, Jan 28, 2015 at 9:02 AM, Roebuck,Paul L > wrote: > > Interrogating some (of my own) code in another package. > > norm.meth <- getMethod("normalize", "MatrixLike") > message("str(norm.meth)") > str(norm.meth) > > > message("show(norm.meth@.Data)") > show(norm.meth@.Data) > > > > Last show() displays this: > > function (object, ...) > { >.local <- function (object, method = c("median", "vs", "tukey"), >calc.medians = TRUE, sweep.cols = calc.medians, >recalc.after.sweep = sweep.cols, ...) >{ >.do_normalize(object, >method = match.arg(method), >calc.medians = calc.medians, >sweep.cols = sweep.cols, >recalc.after.sweep = recalc.after.sweep, >...) >} >.local(object, ...) > } > > > Desire to be able to access formals() for the .local() function definition, > not the generic one. Have seen information desired available via "defined" > slot of returned 'MethodDefinition' object, but not using the code below. > > > > > > library(methods) > > if (!isGeneric("normalize")) { >## Other packages also define this generic... >setGeneric("normalize", > function(object, ...) standardGeneric("normalize")) > } > > setClassUnion("MatrixLike", c("matrix", "data.frame")) > > .do_normalize <- function(concs, > method, > calc.medians, > sweep.cols, > recalc.after.sweep, > ...) { >message("internal routine called!") >NULL > } > > setMethod("normalize", signature(object="MatrixLike"), > function(object, > method=c("median", "vs", "tukey"), > calc.medians=TRUE, > sweep.cols=calc.medians, > recalc.after.sweep=sweep.cols, > ...) { > >.do_normalize <- function(object, >method=match.arg(method), >calc.medians=calc.medians, >sweep.cols=sweep.cols, >recalc.after.sweep=recalc.after.sweep, >...) > } > > __ > R-devel@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel > > > > > > > > [[alternative HTML version deleted]] > > __
Re: [Rd] [Q] Get formal arguments of my implemented S4 method
On Thu, Jan 29, 2015 at 7:57 AM, John Chambers wrote: > > On Jan 28, 2015, at 6:37 PM, Michael Lawrence > wrote: > >> At this point I would just due: >> >> formals(body(method)[[2L]]) >> >> At some point we need to figure out what to do with this .local() confusion. > > Agreed, definitely. The current hack is to avoid re-matching arguments on > method dispatch, so a fix would need to be fairly deep in the implementation. > > But I don't think the expression above is quite right. body(method)[[2L]] is > the assignment. You need to evaluate the rhs. > > Here is a function that does the same sort of thing, and returns the standard > formals for the generic if this method does not have nonstandard arguments. > We should probably add a version of this function for 3.3.0, so user code > doesn't have hacks around the current hack. > > methodFormals <- function(f, signature = character()) { > fdef <- getGeneric(f) > method <- selectMethod(fdef, signature) > genFormals <- base::formals(fdef) > b <- body(method) > if(is(b, "{") && is(b[[2]], "<-") && identical(b[[2]][[2]], > as.name(".local"))) { > local <- eval(b[[2]][[3]]) > if(is.function(local)) > return(formals(local)) > warning("Expected a .local assignment to be a function. Corrupted > method?") > } > genFormals > } I have similar code in roxygen2: # When a generic has ... and a method adds new arguments, the S4 method # wraps the definition inside another function which has the same arguments # as the generic. This function figures out if that's the case, and extracts # the original function if so. # # It's based on expression processing based on the structure of the # constructed method which looks like: # # function (x, ...) { # .local <- function (x, ..., y = 7) {} # .local(x, ...) # } extract_method_fun <- function(x) { fun <- x@.Data method_body <- body(fun) if (!is.call(method_body)) return(fun) if (!identical(method_body[[1]], quote(`{`))) return(fun) first_line <- method_body[[2]] if (!is.call(first_line)) return(fun) if (!identical(first_line[[1]], quote(`<-`))) return(fun) if (!identical(first_line[[2]], quote(`.local`))) return(fun) first_line[[3]] } -- http://had.co.nz/ __ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
Re: [Rd] [Q] Get formal arguments of my implemented S4 method
I wish it didn't have to depend on the name '.local'. Back when I wrote a lot of S4 methods I avoided the auto-generated .local and named the local function something that made sense so that is was easier for a user to track down the source of an error. E.g., define the generic QQQ with numeric and integer methods: setGeneric("QQQ", function(x, ...)NULL) setMethod("QQQ", signature=signature(x="numeric"), function(x, lower, ...) { if (x QQQ(3.4, 10) Error in .local(x, ...) : x traceback() 4: stop("x QQQ(3L, 10) Error in .QQQ.integer(x, ...) : x traceback() 4: stop("x wrote: > On Thu, Jan 29, 2015 at 7:57 AM, John Chambers wrote: > > > > On Jan 28, 2015, at 6:37 PM, Michael Lawrence > wrote: > > > >> At this point I would just due: > >> > >> formals(body(method)[[2L]]) > >> > >> At some point we need to figure out what to do with this .local() > confusion. > > > > Agreed, definitely. The current hack is to avoid re-matching arguments > on method dispatch, so a fix would need to be fairly deep in the > implementation. > > > > But I don't think the expression above is quite right. > body(method)[[2L]] is the assignment. You need to evaluate the rhs. > > > > Here is a function that does the same sort of thing, and returns the > standard formals for the generic if this method does not have nonstandard > arguments. We should probably add a version of this function for 3.3.0, so > user code doesn't have hacks around the current hack. > > > > methodFormals <- function(f, signature = character()) { > > fdef <- getGeneric(f) > > method <- selectMethod(fdef, signature) > > genFormals <- base::formals(fdef) > > b <- body(method) > > if(is(b, "{") && is(b[[2]], "<-") && identical(b[[2]][[2]], > > as.name(".local"))) > { > > local <- eval(b[[2]][[3]]) > > if(is.function(local)) > > return(formals(local)) > > warning("Expected a .local assignment to be a function. > Corrupted method?") > > } > > genFormals > > } > > I have similar code in roxygen2: > > # When a generic has ... and a method adds new arguments, the S4 method > # wraps the definition inside another function which has the same arguments > # as the generic. This function figures out if that's the case, and > extracts > # the original function if so. > # > # It's based on expression processing based on the structure of the > # constructed method which looks like: > # > # function (x, ...) { > # .local <- function (x, ..., y = 7) {} > # .local(x, ...) > # } > extract_method_fun <- function(x) { > fun <- x@.Data > > method_body <- body(fun) > if (!is.call(method_body)) return(fun) > if (!identical(method_body[[1]], quote(`{`))) return(fun) > > first_line <- method_body[[2]] > if (!is.call(first_line)) return(fun) > if (!identical(first_line[[1]], quote(`<-`))) return(fun) > if (!identical(first_line[[2]], quote(`.local`))) return(fun) > > first_line[[3]] > } > > > -- > http://had.co.nz/ > > __ > R-devel@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel > [[alternative HTML version deleted]] __ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
Re: [Rd] [Q] Get formal arguments of my implemented S4 method
I wouldn't want to add more to the current approach; if someone would like to devote some time, the much preferable idea IMO would be to replace the whole mechanism. Here's one suggestion: 1. have a class, say "nonConformingMethod" for method definitions that diverge in the argument list. 2. the internal dispatch code checks the class of the selected definition (this can likely be done with little cost in the standard case). In the case of non-conforming, the arguments are rematched to define the method's other arguments. The possibilities need examining, but my feeling is that the re-matching should happen in the current frame, as opposed to doing a new call. There is a fair amount of code, for example in callNextMethod, that requires some computations using knowledge of the current mechanism. If at some point we required re-installing all packages using non-conforming methods, that code could be made simpler and faster. John On Jan 29, 2015, at 8:08 AM, William Dunlap wrote: > I wish it didn't have to depend on the name '.local'. > > Back when I wrote a lot of S4 methods I avoided the auto-generated .local > and named the local function something that made sense so that is was easier > for a user to track down the source of an error. > > E.g., define the generic QQQ with numeric and integer methods: > setGeneric("QQQ", >function(x, ...)NULL) > setMethod("QQQ", > signature=signature(x="numeric"), > function(x, lower, ...) { > if (x }) > setMethod("QQQ", > signature=signature(x="integer"), > function(x, ...) { > .QQQ.integer <- function(x, lower, ...) if (x stop("x .QQQ.integer(x, ...) > }) > and try using them: > > QQQ(3.4, 10) > Error in .local(x, ...) : x > traceback() > 4: stop("x 3: .local(x, ...) > 2: QQQ(3.4, 10) > 1: QQQ(3.4, 10) > > QQQ(3L, 10) > Error in .QQQ.integer(x, ...) : x > traceback() > 4: stop("x 3: .QQQ.integer(x, ...) at #5 > 2: QQQ(3L, 10) > 1: QQQ(3L, 10) > I think the latter gives the user more guidance on how to fix the problem. > > Perhaps instead of searching for an assignment to '.local' you could > search for an assignment to the name of the function used in the last > function call of the method. > > > > Bill Dunlap > TIBCO Software > wdunlap tibco.com > > On Thu, Jan 29, 2015 at 6:34 AM, Hadley Wickham wrote: > On Thu, Jan 29, 2015 at 7:57 AM, John Chambers wrote: > > > > On Jan 28, 2015, at 6:37 PM, Michael Lawrence > > wrote: > > > >> At this point I would just due: > >> > >> formals(body(method)[[2L]]) > >> > >> At some point we need to figure out what to do with this .local() > >> confusion. > > > > Agreed, definitely. The current hack is to avoid re-matching arguments on > > method dispatch, so a fix would need to be fairly deep in the > > implementation. > > > > But I don't think the expression above is quite right. body(method)[[2L]] > > is the assignment. You need to evaluate the rhs. > > > > Here is a function that does the same sort of thing, and returns the > > standard formals for the generic if this method does not have nonstandard > > arguments. We should probably add a version of this function for 3.3.0, so > > user code doesn't have hacks around the current hack. > > > > methodFormals <- function(f, signature = character()) { > > fdef <- getGeneric(f) > > method <- selectMethod(fdef, signature) > > genFormals <- base::formals(fdef) > > b <- body(method) > > if(is(b, "{") && is(b[[2]], "<-") && identical(b[[2]][[2]], > > as.name(".local"))) { > > local <- eval(b[[2]][[3]]) > > if(is.function(local)) > > return(formals(local)) > > warning("Expected a .local assignment to be a function. Corrupted > > method?") > > } > > genFormals > > } > > I have similar code in roxygen2: > > # When a generic has ... and a method adds new arguments, the S4 method > # wraps the definition inside another function which has the same arguments > # as the generic. This function figures out if that's the case, and extracts > # the original function if so. > # > # It's based on expression processing based on the structure of the > # constructed method which looks like: > # > # function (x, ...) { > # .local <- function (x, ..., y = 7) {} > # .local(x, ...) > # } > extract_method_fun <- function(x) { > fun <- x@.Data > > method_body <- body(fun) > if (!is.call(method_body)) return(fun) > if (!identical(method_body[[1]], quote(`{`))) return(fun) > > first_line <- method_body[[2]] > if (!is.call(first_line)) return(fun) > if (!identical(first_line[[1]], quote(`<-`))) return(fun) > if (!identical(first_line[[2]], quote(`.local`))) return(fun) > > first_line[[3]] > } > > > -- > http://had.co.nz/ > > __ > R-devel@r-project.org mailing list > https://stat.ethz.ch/mailma
Re: [Rd] [Q] Get formal arguments of my implemented S4 method
Would we really need the special class or would simply checking the formals of the method against those of the generic be simple and fast enough? On Thu, Jan 29, 2015 at 9:41 AM, John Chambers wrote: > I wouldn't want to add more to the current approach; if someone would like > to devote some time, the much preferable idea IMO would be to replace the > whole mechanism. > > Here's one suggestion: > > 1. have a class, say "nonConformingMethod" for method definitions that > diverge in the argument list. > > 2. the internal dispatch code checks the class of the selected definition > (this can likely be done with little cost in the standard case). In the > case of non-conforming, the arguments are rematched to define the method's > other arguments. > > The possibilities need examining, but my feeling is that the re-matching > should happen in the current frame, as opposed to doing a new call. > > There is a fair amount of code, for example in callNextMethod, that > requires some computations using knowledge of the current mechanism. If at > some point we required re-installing all packages using non-conforming > methods, that code could be made simpler and faster. > > John > > > > > On Jan 29, 2015, at 8:08 AM, William Dunlap wrote: > > > I wish it didn't have to depend on the name '.local'. > > > > Back when I wrote a lot of S4 methods I avoided the auto-generated .local > > and named the local function something that made sense so that is was > easier > > for a user to track down the source of an error. > > > > E.g., define the generic QQQ with numeric and integer methods: > > setGeneric("QQQ", > >function(x, ...)NULL) > > setMethod("QQQ", > > signature=signature(x="numeric"), > > function(x, lower, ...) { > > if (x > }) > > setMethod("QQQ", > > signature=signature(x="integer"), > > function(x, ...) { > > .QQQ.integer <- function(x, lower, ...) if (x stop("x > .QQQ.integer(x, ...) > > }) > > and try using them: > > > QQQ(3.4, 10) > > Error in .local(x, ...) : x > > traceback() > > 4: stop("x > 3: .local(x, ...) > > 2: QQQ(3.4, 10) > > 1: QQQ(3.4, 10) > > > QQQ(3L, 10) > > Error in .QQQ.integer(x, ...) : x > > traceback() > > 4: stop("x > 3: .QQQ.integer(x, ...) at #5 > > 2: QQQ(3L, 10) > > 1: QQQ(3L, 10) > > I think the latter gives the user more guidance on how to fix the > problem. > > > > Perhaps instead of searching for an assignment to '.local' you could > > search for an assignment to the name of the function used in the last > > function call of the method. > > > > > > > > Bill Dunlap > > TIBCO Software > > wdunlap tibco.com > > > > On Thu, Jan 29, 2015 at 6:34 AM, Hadley Wickham > wrote: > > On Thu, Jan 29, 2015 at 7:57 AM, John Chambers > wrote: > > > > > > On Jan 28, 2015, at 6:37 PM, Michael Lawrence < > lawrence.mich...@gene.com> wrote: > > > > > >> At this point I would just due: > > >> > > >> formals(body(method)[[2L]]) > > >> > > >> At some point we need to figure out what to do with this .local() > confusion. > > > > > > Agreed, definitely. The current hack is to avoid re-matching > arguments on method dispatch, so a fix would need to be fairly deep in the > implementation. > > > > > > But I don't think the expression above is quite right. > body(method)[[2L]] is the assignment. You need to evaluate the rhs. > > > > > > Here is a function that does the same sort of thing, and returns the > standard formals for the generic if this method does not have nonstandard > arguments. We should probably add a version of this function for 3.3.0, so > user code doesn't have hacks around the current hack. > > > > > > methodFormals <- function(f, signature = character()) { > > > fdef <- getGeneric(f) > > > method <- selectMethod(fdef, signature) > > > genFormals <- base::formals(fdef) > > > b <- body(method) > > > if(is(b, "{") && is(b[[2]], "<-") && identical(b[[2]][[2]], > as.name(".local"))) { > > > local <- eval(b[[2]][[3]]) > > > if(is.function(local)) > > > return(formals(local)) > > > warning("Expected a .local assignment to be a function. > Corrupted method?") > > > } > > > genFormals > > > } > > > > I have similar code in roxygen2: > > > > # When a generic has ... and a method adds new arguments, the S4 method > > # wraps the definition inside another function which has the same > arguments > > # as the generic. This function figures out if that's the case, and > extracts > > # the original function if so. > > # > > # It's based on expression processing based on the structure of the > > # constructed method which looks like: > > # > > # function (x, ...) { > > # .local <- function (x, ..., y = 7) {} > > # .local(x, ...) > > # } > > extract_method_fun <- function(x) { > > fun <- x@.Data > > > > method_body <- body(fun) > > if (!is.call(method_body)) return(fun) > > if (!id
Re: [Rd] [Q] Get formal arguments of my implemented S4 method
Some experimenting is needed. But I think a subclass is likely to be cleaner. The official model is that methods and generic differ only in the body, so having an object-based way to say that some methods are non-conforming feels more natural to me. On Jan 29, 2015, at 9:57 AM, Michael Lawrence wrote: > Would we really need the special class or would simply checking the formals > of the method against those of the generic be simple and fast enough? > > On Thu, Jan 29, 2015 at 9:41 AM, John Chambers wrote: > >> I wouldn't want to add more to the current approach; if someone would like >> to devote some time, the much preferable idea IMO would be to replace the >> whole mechanism. >> >> Here's one suggestion: >> >> 1. have a class, say "nonConformingMethod" for method definitions that >> diverge in the argument list. >> >> 2. the internal dispatch code checks the class of the selected definition >> (this can likely be done with little cost in the standard case). In the >> case of non-conforming, the arguments are rematched to define the method's >> other arguments. >> >> The possibilities need examining, but my feeling is that the re-matching >> should happen in the current frame, as opposed to doing a new call. >> >> There is a fair amount of code, for example in callNextMethod, that >> requires some computations using knowledge of the current mechanism. If at >> some point we required re-installing all packages using non-conforming >> methods, that code could be made simpler and faster. >> >> John >> >> >> >> >> On Jan 29, 2015, at 8:08 AM, William Dunlap wrote: >> >>> I wish it didn't have to depend on the name '.local'. >>> >>> Back when I wrote a lot of S4 methods I avoided the auto-generated .local >>> and named the local function something that made sense so that is was >> easier >>> for a user to track down the source of an error. >>> >>> E.g., define the generic QQQ with numeric and integer methods: >>> setGeneric("QQQ", >>> function(x, ...)NULL) >>> setMethod("QQQ", >>> signature=signature(x="numeric"), >>> function(x, lower, ...) { >>> if (x>> }) >>> setMethod("QQQ", >>> signature=signature(x="integer"), >>> function(x, ...) { >>> .QQQ.integer <- function(x, lower, ...) if (x> stop("x>> .QQQ.integer(x, ...) >>> }) >>> and try using them: QQQ(3.4, 10) >>> Error in .local(x, ...) : x>>> traceback() >>> 4: stop("x>> 3: .local(x, ...) >>> 2: QQQ(3.4, 10) >>> 1: QQQ(3.4, 10) QQQ(3L, 10) >>> Error in .QQQ.integer(x, ...) : x>>> traceback() >>> 4: stop("x>> 3: .QQQ.integer(x, ...) at #5 >>> 2: QQQ(3L, 10) >>> 1: QQQ(3L, 10) >>> I think the latter gives the user more guidance on how to fix the >> problem. >>> >>> Perhaps instead of searching for an assignment to '.local' you could >>> search for an assignment to the name of the function used in the last >>> function call of the method. >>> >>> >>> >>> Bill Dunlap >>> TIBCO Software >>> wdunlap tibco.com >>> >>> On Thu, Jan 29, 2015 at 6:34 AM, Hadley Wickham >> wrote: >>> On Thu, Jan 29, 2015 at 7:57 AM, John Chambers >> wrote: On Jan 28, 2015, at 6:37 PM, Michael Lawrence < >> lawrence.mich...@gene.com> wrote: > At this point I would just due: > > formals(body(method)[[2L]]) > > At some point we need to figure out what to do with this .local() >> confusion. Agreed, definitely. The current hack is to avoid re-matching >> arguments on method dispatch, so a fix would need to be fairly deep in the >> implementation. But I don't think the expression above is quite right. >> body(method)[[2L]] is the assignment. You need to evaluate the rhs. Here is a function that does the same sort of thing, and returns the >> standard formals for the generic if this method does not have nonstandard >> arguments. We should probably add a version of this function for 3.3.0, so >> user code doesn't have hacks around the current hack. methodFormals <- function(f, signature = character()) { fdef <- getGeneric(f) method <- selectMethod(fdef, signature) genFormals <- base::formals(fdef) b <- body(method) if(is(b, "{") && is(b[[2]], "<-") && identical(b[[2]][[2]], >> as.name(".local"))) { local <- eval(b[[2]][[3]]) if(is.function(local)) return(formals(local)) warning("Expected a .local assignment to be a function. >> Corrupted method?") } genFormals } >>> >>> I have similar code in roxygen2: >>> >>> # When a generic has ... and a method adds new arguments, the S4 method >>> # wraps the definition inside another function which has the same >> arguments >>> # as the generic. This function figures out if that's the case, and >> extracts >>> # the original function if so. >>> # >>> # It's based on expression processing based on the
Re: [Rd] names function for environments?
> Yea, but it is super weird that as.list() filters elements out of the > environment during coercion. > > I think I'm going to look through the uses of ls() inside of the core > packages, because I suspect that is usually not necessary to extract the > keys, and there is a cleaner (and probably faster) way to achieve the same > result. It would be nice to have a function that generalised over exists("x", env = y) and "x" %in% names(y). Hadley -- http://had.co.nz/ __ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel