Dynamically Generate Reference Classes
Asked Answered
S

1

13

I'm attempting to generate reference classes within an R package on the fly, and it's proving to be fairly difficult. Here are the approaches I've taken and problems I've run into:

I'm creating a package in which I hope to be able to dynamically read in a schema and automatically generate an associated reference class (think SOAP). Of course, this means I won't be able to define my reference classes before-hand in the package sources.

I initially attempted to create a new class using a simple:

myClass <- setRefClass("NewClassName", fields=list(fieldA="character"))

which, of course, works fine when executed interactively, but when included in the package sources, I get a locked binding error. From my reading, it looks like this occurs because when running interactively, the class information is being stored in the global environment, which is not locked, while my package's base environment is locked.

I then found a thread that suggested using something to the effect of:

myClass <- setRefClass("NewClassName", fields=list(fieldA="character"), where=globalenv())

This actually crashed R/Studio when I tried to build the package, so I don't have a log of the error it generated, unfortunately, but it certainly didn't work.

Next I tried creating a new environment within my package which I could use to store these reference classes. So I added a .classEnv <- new.env() line in my package sources (not inside of any function) and then attempted to use this class when creating a new reference class:

myClass <- setRefClass("NewClassName", fields=list(fieldA="character"), where=.classEnv) 

This actually seemed to work OK, but generates the following warning:

> myClass <- setRefClass("NewClassName", where=.classEnv)
Warning message:
In getPackageName(where) :
  Created a package name, ‘2013-04-23 10:19:14’, when none found

So, for some reason, methods::getPackageName() isn't able to pick up which package my new environment is in?

Is there a way to create my new environment differently so that getPackageName() can properly recognize the package? Can I add some feature which allows me to help getPackageName() detect the package? Will this even work if I can deal with the warning, or am I misusing reference classes by trying to create them dynamically?

Stylography answered 23/4, 2013 at 15:43 Comment(2)
?setRefClass says that arguments ... are passed to ?setClass, and this has argument package; do you want to take your third approach, with argument package='YourPackage' or something?Paco
Thanks for the tip, Martin. Unfortunately, that wasn't able to remove the error. It looks like the package name doesn't trickle all the way down to getPackageName which is where the warning comes from if the .packageName variable hasn't already been specified.Stylography
S
5

To get the conversation going, I found that getpackageName stores the package name in a hidden .packageName variable in the specified environment.

So you can actually get around the warning with

assign(".packageName", "MyPkg", envir=.classEnv)    
myClass <- setRefClass("NewClassName", fields=classFields, where=.classEnv)

which resolves the warning, but the documentation says not to trust the .packageName variable indefinitely, and I still feel like I'm hacking this in and may be misunderstanding something important about reference classes and their relationship to environments.

Full details from documentation:

Package names are normally installed during loading of the package, by the INSTALL script or by the library function. (Currently, the name is stored as the object .packageName but don't trust this for the future.)


Edit:

After reading a little further, the setPackageName method may be a more reliable way to set the package name for the environment. Per the docs:

setPackageName can be used to establish a package name in an environment that would otherwise not have one. This allows you to create classes and/or methods in an arbitrary environment, but it is usually preferable to create packages by the standard R programming tools (package.skeleton, etc.)

So it looks like one valid solution would be the following:

setPackageName("MyPkg", .classEnv)
myClass <- setRefClass("NewClassName", fields=classFields, where=.classEnv)

That eliminates the warning message and doesn't rely on anything that's documented as unstable. I'm still not clear why it's necessary, but...

Stylography answered 23/4, 2013 at 15:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.