My favorites | Sign in
Project Logo
             

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.Antoine de Saint Exupéry

Inside every large program there is a small program trying to get out.Sir Tony Hoare

Below on this page are sections on:

Introduction

proto (google code name r-proto) is an R package which facilitates a style of programming known as prototype-based programming. Prototype-based programming is a type of object oriented programming in which classes and objects are unified into a single concept, prototypes. This makes proto and prototye programming, in general, simpler yet it retains the object oriented features of delegation (the prototype counterpart to inheritance) and object oriented dispatch. Applications, News, Additional Information sources, Proto Bugs and Avoiding R Bugs sections are given below.

Applications

The following R packages use or are typically used with proto:

Although there is no way to know the totality of applications using proto we do know that the proto web site (this page and associated pages) is listed 5th among the googlecode sites labelled R as of April 5, 2009. According to Google Analytics the proto web site receives 151% more hits (i.e. 2.51x as many) than the average open software site of its size based on data for the month ending October 21, 2008.

News

Jun 5/09. Added information (see above) on the sqldf R package which uses proto internally.

Apr 5/09. Added information (see above) on the ascii R package which uses proto internally.

Oct 3/08. Updated links to Lieberman (1986) and Taivalsaari (1996) papers in the Links box to the right.

Oct 3/08. Confirmed that the LazyLoad bug in R is still present. See the first point in the Avoiding R Bugs section below and this r-devel post.

July 5/08. Added a fifth point in the Avoiding R Bugs section.

May 19/08. Added quotations to top of this page.

Mar 7/08. In the development version of proto the parent argument to the proto function may now be a function in which case its environment is used as the parent. This facilitates constructing proxy proto objects: with(proto(f, f = f, a = 1), f) wedges an anonymous proto object between f and its environment inserting a into the proxy so that it can be accessed as a free variable from within f.

Mar 7/08. The method of proto proxies was illustrated in an r-devel post.

Feb 25/08. A dput.proto routine was posted on r-devel.

Jan 26/08. Just noticed that there was a modification to the R development source made on Jan 24, 2008, see r44139 in r-devel log, which indicates that a bug in R related to promises has been fixed. Since proto 0.4, the current development version, depends heavily on promises this should be beneficial. The following code, which is not dependent on proto, previously failed under R but now it works:

# code below previously triggered errors but now works - R 2.6.2 (2008-01-26 r44181)

f <- function(x) environment()
z <- as.list(f(7))
dput(z)
structure(list(x = 7), .Names = "x")
z[[1]] == 7  # should return TRUE
force(z[[1]]) == 7 # should return TRUE

Jan 09/08. Added a second paragraph to the LazyLoad subsection of the Avoiding R Bugs list at the bottom based on a recent discussion on the r-devel list. Also added a new section Proto Bugs below. Note that all known bugs are fixed in the development version of proto.

Dec 07/07. as.proto.data.frame method added to the devel version of proto. Its just a synonym for as.proto.list.

as.proto.data.frame <- as.proto.list

Dec 06/07. print bug added to bug list below.

Dec 01/07. Added a new argument, eval.env = parent.frame() to the proto function in the devel version of proto. It defines the environment in which promises in the ... arguments are evaluated. The default value of eval.env is normally what one wants; however, in the case of wrappers around proto one would generally want the calling frame of the wrapper rather than the frame which directly calls proto and this argument facilitates that. The need for this is related to the problem in R described in point #4 of Avoiding R Bugs at the end of this page.

Oct 28/07. Added a reference to pmg in the Applications section above as it uses proto internally.

Oct 17/07. Added a reference to this r-devel post and discussion to the LazyLoad subsection of the Avoiding R Bugs section at the end of this page. (This applies to packages that have proto objects at top level. Also see ReleaseNotes.txt.)

Sep 30/07. A workaround for the R bug where promises in lists do not get evaluated was developed. (This never affected the released version of proto on CRAN.) See Avoiding R Bugs section below.

Sep 25/07. Added ReleaseNotes.txt describing new features of the development version (proto 0.4-0) also found on Source tab above. To try out, after installing from the Source Repository run this (under R 2.6.2):

library(proto)
example(proto)
demo(proto)
demo("proto-vignette")
demo("proto-gWidgets") # needs gWidgets package to be installed

or to try it without installing anything (other than CRAN version of proto):

library(proto) # loads CRAN version of proto
source("http://r-proto.googlecode.com/svn/trunk/R/proto.R") # load changed code
demo(proto)
source("http://r-proto.googlecode.com/svn/trunk/demo/demo-vignette.R")
source("http://r-proto.googlecode.com/svn/trunk/demo/demo-gWidgets.R")

Sep 20/07. John Verzani has added another proto/gWidgets user interface example here. It is in addition to his others here and here. Also see this r-devel post for another proto/gWidgets example.

Sep 15/07. proto 0.3-8 uploaded to CRAN. Only changes are those needed to satisfy R 2.6.0.

Citation

To get the citation for this package use the R command:

citation("proto")

Additional Information

Additional information is available at:

Proto Bugs

The following are bugs in the released version of proto on CRAN. They are all fixed in the development version already.

1. str.proto. This will not affect most users but one user was redefining print and that caused name.proto (hence str.proto) to break. The call to print has been replaced with a call to print.default in name.proto to avoid this in the devel version of proto. Here are three workarounds in the meantime: Run this code:

name.proto <- proto(print.proto = print.default, f = proto::name.proto)$f

or, source the new version of graph.proto.R which is the file that contains name.proto:

source("http://r-proto.googlecode.com/svn/trunk/R/proto.R") # load changed code

or, ensure that your proto object has a ..Name component. For example, this works even if print is redefined:

print <- function(x, ...) 1
p <- proto(..Name = "proto object: p", x = 1)
name.proto(p)
str(p)
rm(print)

2. A proto object could not have the name x.

Avoiding R Bugs

Due to the fundamental nature of proto, it makes use of portions of R that may not be commonly accessed in other packages; therefore, it has uncovered a number of R bugs or deficencies that were not previously known or at least are less known. Fortunately there are simple workarounds to deal with them provided you know about them.

1. LazyLoad

If a package uses lazyloading then R will erroneously change the class of all proto objects at top level to "environment". This r-devel post from the R development team confirms that it is a bug in R and that there is an intention to fix it (however, as of "R version 2.8.0 alpha (2008-10-01 r46589)" it had still not been fixed. See this r-devel post for details and info on how to test it.) To avoid this bug use LazyLoad: false in the DESCRIPTION file of any package that has proto objects at top level.

In older versions of R it was possible to use SaveImage: true in the DESCRIPTION file; however, SaveImage is not available in recent versions of R.

One gotcha is that not specifying LazyLoad is not the same as LazyLoad: false. As mentioned in R News 4/2 if LazyLoad is not specified then R will use lazy loading if there is more than 25K of R code in the package and otherwise not. See this: r-devel discussion. There is some information on LazyLoad and SaveImage in this r-devel post and there is an article on lazy loading in R News 4/2. (This behavior will change in R 2.9.0 where true will be the default and the odd 25K criterion will be eliminated.)

One can test this by creating an R package with only two files which are (1) this DESCRIPTION file:

Package: testlazy
Version: 1.0-0
Date: 2008-10-03
Title: Test lazy loading
Author: G Grothendieck
Maintainer: G Grothendieck <ggrothendieck@gmail.com>
Description: Test lazy loading with top level objects.
Depends: proto
LazyLoad: yes
License: GPL-2

and (2) this R/testlazy.R file:

TopLevel <- proto()

We test it like this:

library(testlazy)
class(TopLevel)

If the class of TopLevel is just environment then the proto component of the class has been stripped by R.

One related problem is that if you use LazyLoad: false to overcome the problem above then proto will not be available during the package load unless it is specifically loaded so add: require(proto) to your code if any top level proto objects are created at load time. See: this r-devel post and this related post .

2. Promises and Lists

R is supposed to evaluate promises that are stored in lists but, in fact, it does not -- see this thread in r-devel. It is currently believed that this has never affected the released version of proto on CRAN nor does it affect the most recent devel version of proto. It did affect earlier devel versions of proto. Even though it seems to currently have no consequence we are leaving this item here just in case it comes up in some new form and needs to be revisited. (This may be fixed already in the R 2.9.0 development version.)

# No longer a problem but recorded here just in case.

# ensure proto 0.4-0 is installed from Source tab 
# or just load the CRAN version of proto and over top
# of it source proto.R from the repository as discussed 
# in the Sep 25th News item above
# 
# in the code below:
# - p is a proto object 
# - x a child of p created by invoking p$new
# - y is a copy of x formed by converting the
#   the proto object to a list and back to proto
#
# The problem is that although ls(y) says that gg is in y
# when we try to evaluate it, R says its not there.

p <- proto(, {
	Name <- gg <- "m" # for debugging. Can omit this line.
	new <- function(., gg) proto(., Name = "n", gg = gg)
})
# one clue is that if we
# uncomment next line and comment one after it error disappears
# x <- proto(gg = "g")
x <- p$new(gg = "g") # x is a child of p
x$Name <- "x" # for debugging.  Can omit this line.
y <- as.proto(as.list(x)) # y is a copy of x
y$Name <- "y"  # for debugging.  Can omit this line.
ls(y) # shows that gg in y
# next line gives error saying gg not found
with(y, gg)

3. Subclassing environments

Operating locally on an environment attribute changes its value globally which seems undesirable.

The proto class is an S3 subclass of the environment class. Unfortunately if e is a variable holding an environment and f is a copy of it then if you set an attribute on f then e gets it too:

f <- e
attr(f, "abc") <- 3

After the above e will gain attribute abc with a value of 3 as well. This occurs even if 3 is assigned within a function. "class" is an attribute so it also applies to the class.

4. Limitations on Use of Promises

Using pure R, there is currently no way to copy promises without evaluating them nor is there any way to discover the environment associated with a promise. For the proto clone function it would be desirable to be able to copy promises without evaluating them while preserving their environments. Although the preceding are not possible in pure R it is possible to do this using C.

5. [[ Does Not Work Well with Promises

In the code below test fails. Note that this code does not use proto and this is a general problem in R (this has been fixed in R 2.9.0 development version):

idx <- 2

# Error !!!
test <- function(pf = parent.frame()) BOD[[pf$idx]]
test()

# Returns expected result by avoiding [[
test2 <- function(pf = parent.frame()) .subset2(BOD, pf$idx)
test2()

# Also works as expected by forcing pf so its not a promise 
test3 <- function(pf = parent.frame()) { force(pf); BOD[[pf$idx]] }
test3()

# Also works as expected.  Surprisingly [[.data.frame gives different result than [[ 
# See https://stat.ethz.ch/pipermail/r-devel/2008-July/050126.html
test4 <- function(pf = parent.frame()) "[[.data.frame"(BOD, pf$idx)
test4()








Hosted by Google Code