On 05/08/2013 10:25 AM, Simon Urbanek wrote:

On May 7, 2013, at 11:35 PM, Peter Meilstrup wrote:

Encountered an error in scripting, which can be reproduced using Rscript as
follows:

$ Rscript -e "library(httr); handle('http://cran.r-project.org')"

Error in getCurlHandle(cookiefile = cookie_path, .defaults = list()) :
  could not find function "getClass"
Calls: handle -> getCurlHandle

or by starting R without the methods package attached:

$ R_DEFAULT_PACKAGES=base R
[snip]
library(httr)
handle('http://cran.fhcrc.org/')
Error in getCurlHandle(cookiefile = cookie_path, .defaults = list()) :
  could not find function "getClass"

As far as I can tell the error occurs when getCurlHandle .Calls a C
function which then calls SET_CLASS, which (I guess) requires
methods::setClass to be in the search path.

Now 'httr' Imports 'RCurl' which Depends on 'methods'. So I think
`library(httr)` should end up attaching 'methods' to the search path, but
it seems 'methods' is just imported to RCurl's namespace.

I think this is a problem since the Depends line is indicating that
'methods' must be attached for RCurl to work, whether or not RCurl itself
is being attached.


For the record, I see the same problem with other packages that use S4 - very 
often it trips packages that don't use S4 but import a package that does. The 
analysis is correct - if a package B just imports a function from another 
package A which in turn relies on something in Depends, it breaks, because A is 
not on the search path and thus A doesn't have access to the dependencies it 
needs. I don't know that was the intended design. I see two way to fix this
1) make sure Depends: are always put on the search path even if the package is 
not attached
2) automatically generate imports for all packages in Depends:

The main problem is that B is helpless - only a change in A can make it work. 
Fix for A is to explicitly add import(methods) even though it's already in 
Depends:. Note that R CMD check doesn't detect this.

As described, this is a 'package maintainer' problem -- fix package A. Also, this isn't unique to methods, other packages routinely Depend: on something that should instead be Import:'ed.

But I think Peter's case is different, because the C implementations of

    SEXP R_do_MAKE_CLASS(const char *what);
    SEXP R_getClassDef  (const char *what);

need to be called from inside the package environment, but there is no way to pass the package environment through the interface above.

Maybe the partial patch (attached) points to a solution? It changes the interface (though would only break a couple of Bioconductor packages in a minor way) (I think there's a missing PROTECT in there too.)



Cheers,
Simon

______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel



--
Computational Biology / Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N.
PO Box 19024 Seattle, WA 98109

Location: Arnold Building M1 B861
Phone: (206) 667-2793
Index: src/include/Rinternals.h
===================================================================
--- src/include/Rinternals.h	(revision 62721)
+++ src/include/Rinternals.h	(working copy)
@@ -891,8 +891,8 @@
 int R_has_slot(SEXP obj, SEXP name);
 
 /* class definition, new objects (objects.c) */
-SEXP R_do_MAKE_CLASS(const char *what);
-SEXP R_getClassDef  (const char *what);
+SEXP R_do_MAKE_CLASS(const char *what, SEXP rho);
+SEXP R_getClassDef  (const char *what, SEXP rho);
 SEXP R_do_new_object(SEXP class_def);
 /* supporting  a C-level version of  is(., .) : */
 int R_check_class_and_super(SEXP x, const char **valid, SEXP rho);
Index: src/include/Rdefines.h
===================================================================
--- src/include/Rdefines.h	(revision 62721)
+++ src/include/Rdefines.h	(working copy)
@@ -139,7 +139,8 @@
 #define GET_SLOT(x, what)       R_do_slot(x, what)
 #define SET_SLOT(x, what, value)  R_do_slot_assign(x, what, value)
 
-#define MAKE_CLASS(what)	R_do_MAKE_CLASS(what)
+#define MAKE_CLASS(what)	R_do_MAKE_CLASS(what, R_GlobalEnv)
+#define GET_CLASS_DEF(what)	R_getClassDef(what, R_GlobalEnv)
 /* NEW_OBJECT is recommended; NEW is for green book compatibility */
 #define NEW_OBJECT(class_def)	R_do_new_object(class_def)
 #define NEW(class_def)		R_do_new_object(class_def)
Index: src/main/objects.c
===================================================================
--- src/main/objects.c	(revision 62721)
+++ src/main/objects.c	(working copy)
@@ -864,7 +864,7 @@
 
 #ifdef _be_too_picky_
     if(IS_S4_OBJECT(x) && nwhat == 1 && !isvec &&
-       !isNull(R_getClassDef(translateChar(STRING_ELT(what, 0)))))
+       !isNull(R_getClassDef(translateChar(STRING_ELT(what, 0))))) /* FIXME: needs rho */
 	warning(_("use 'is()' instead of 'inherits()' on S4 objects"));
 #endif
 
@@ -937,7 +937,7 @@
 	    s_selectSuperCl = install(".selectSuperClasses");
 	}
 
-	PROTECT(classExts = R_do_slot(R_getClassDef(class), s_contains));
+	PROTECT(classExts = R_do_slot(R_getClassDef(class, rho), s_contains));
 	PROTECT(_call = lang3(s_selectSuperCl, classExts,
 			      /* dropVirtual = */ ScalarLogical(1)));
 	superCl = eval(_call, rho);
@@ -1470,7 +1470,7 @@
 	return value;
 }
 
-SEXP R_do_MAKE_CLASS(const char *what)
+SEXP R_do_MAKE_CLASS(const char *what, SEXP rho)
 {
     static SEXP s_getClass = NULL;
     SEXP e, call;
@@ -1480,13 +1480,13 @@
     PROTECT(call = allocVector(LANGSXP, 2));
     SETCAR(call, s_getClass);
     SETCAR(CDR(call), mkString(what));
-    e = eval(call, R_GlobalEnv);
+    e = eval(call, rho);
     UNPROTECT(1);
     return(e);
 }
 
 /* this very similar, but gives NULL instead of an error for a non-existing class */
-SEXP R_getClassDef(const char *what)
+SEXP R_getClassDef(const char *what, SEXP rho)
 {
     static SEXP s_getClassDef = NULL;
     SEXP e, call;
@@ -1496,7 +1496,7 @@
     PROTECT(call = allocVector(LANGSXP, 2));
     SETCAR(call, s_getClassDef);
     SETCAR(CDR(call), mkString(what));
-    e = eval(call, R_GlobalEnv);
+    e = eval(call, rho);
     UNPROTECT(1);
     return(e);
 }
@@ -1520,12 +1520,13 @@
 	      translateChar(asChar(e)));
     }
     e = R_do_slot(class_def, s_className);
-    value = duplicate(R_do_slot(class_def, s_prototype));
+    PROTECT(value = duplicate(R_do_slot(class_def, s_prototype)));
     if(TYPEOF(value) == S4SXP || getAttrib(e, R_PackageSymbol) != R_NilValue)
     { /* Anything but an object from a base "class" (numeric, matrix,..) */
 	setAttrib(value, R_ClassSymbol, e);
 	SET_S4_OBJECT(value);
     }
+    UNPROTECT(1);
     return value;
 }
 
______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

Reply via email to