From jmc at r-project.org  Fri Jan 14 20:51:48 2005
From: jmc at r-project.org (John Chambers)
Date: Fri Jan 14 20:52:19 2005
Subject: [Rd] RE: [R] as.character methods
In-Reply-To: <67DCA285A2D7754280D3B8E88EB5480206741E16@MSGBOSCLB2WIN.DMN1.FMR.COM>
References: <67DCA285A2D7754280D3B8E88EB5480206741E16@MSGBOSCLB2WIN.DMN1.FMR.COM>
Message-ID: <41E822D4.9070107@R-project.org>



McGehee, Robert wrote:
> Thank you for your replies. I greatly appreciate the wealth of
> documentation on this subject and the time spent by the John Chambers
> and the R Core Team making object-orient programming in R a reality. I
> hope to be able to give code (not just bug reports) back to the R
> community as my projects advance.
> 
> I hoping to generalize my as.character question to a real-life
> as.character / print method example that is causing more problems than
> I'd like to admit, and that I hope I could get feedback from.
> 
> Briefly, I'm looking to extend the "name" class into a new class 

Unfortunately there is a major catch here.  Objects of class "name" are 
not duplicated by the internal R code, in contrast to the normal model 
for objects in R.  In other words, any variable containing a particular 
name is a reference to one copy of that name.

This effectively prevents building subclasses of "name", as well as many 
other computations.  The following example illustrates the problem:

R> x = as.name('foo')
R> x
foo
R> y = x
R> attr(x, "bar") = "test"
R> y
foo
attr(,"bar")
[1] "test"

The attribute that is set in one object appears in the other.

(Similar problems arise with environment objects and some other classes.)

In the future, it might be possible to let such objects have attributes 
that were treated normally, while the objects still pointed to the 
single name or environment.

For now, though, it's necessary to protect the object by having the name 
as a slot or element of a list, not as a class simply extending "name".

I call
> "newName" which performs just as "name" does except that when a
> "newName" object is printed that has been initialized without a value,
> it prints NULL to the screen instead of `<UNDEFINED>`. I chose the
> "name" class as I am using extensions of name, call, and expression to
> create syntactically correct R expressions that are then parsed by a
> non-R parser. Thus I want to be able use R to check for syntax and
> "translate" code from one language into another.
> 
> My problem is that I have been unable to make the print method work
> correctly on the "name" class, despite success for other classes, and my
> best implementation only sometimes works (sometimes it prints, sometimes
> it errors out). The below code produces the behavior that the first time
> we try to print the object we get an error, the second time it prints
> correctly, and the third and fourth time it prints, but without quotes.
> To run the following code to reproduce my problem, you may need to
> restart R to see exactly the same behavior that I am seeing on Windows /
> Linux 2.0.1. As always, I'd appreciate any help in creating this method,
> or comments on my approach, as I effectively want to hide the
> `<UNDEFINED>` initialization of this new object.
> 
> ######################
> ## First create the class as extension of "name"
> setClass("newName",
>          representation("name"))
> 
> ## Write a generator function for this class
> newName <- function(value) {
>     if (missing(value) || is.null(value))
>       x <- new("name")
>     else
>       x <- as.name(value)
>     class(x) <- "newName"
>     x
> }
> 
> ## as.character method for printing:
> as.character.newName <- function(x, ...) {
>     ## If x is the same as an uninitialized "newName" object, then
> return NULL
>     if(x == new("newName"))
>       return(NULL)
>     else
>       as.character(as.name(x))
> }
> 
> ## The print method should just reference the 
> ## as.character method
> print.newName <- function(x, ...) {
>     as.character(x, ...)
> }
> 
> ## Now create the object.
> a <- newName("abc")
> ## Thus "a" has class of "newName" and holds the symbol `abc`
> 
> ############
> ## Now let's try to look at this object using print()
> ############
> 
>>a
> 
> Error in print(abc) : Object "abc" not found
> ## Fails! Let's try calling print() explicitly
> 
> 
>>print(a)
> 
> [1] "abc"
> ## That worked, let's try looking at the object again
> 
> 
>>a
> 
> abc
> ## This time it printed! (without the quotes)
> 
> ## Let's try printing the object again
> 
>>print(a)
> 
> abc 
> ## Again, printed without the quotes
> 
> If I create formal methods for print, show, and/or as.character, I still
> have similar problems, and in no case can I get this to work
> (consistently at least). Should I abandon trying to extend the "name"
> class at all? Or is there some problems in my code above that would
> cause this behavior. I have not had any similar trouble when extending
> the "call" and "expression" classes, and apologies for the technical
> nature of this post.
> 
> Thanks,
> Robert
> 
> 
> -----Original Message-----
> From: John Chambers [mailto:jmc@r-project.org] 
> Sent: Friday, January 14, 2005 10:36 AM
> To: Prof Brian Ripley
> Cc: McGehee, Robert; r-devel@stat.math.ethz.ch
> Subject: Re: [Rd] RE: [R] as.character methods
> 
> 
> 
> 
> Prof Brian Ripley wrote:
>  > Please use R-devel not R-help for esoteric programming questions: I
> have
>  > moved this there.  [See the posting guide.]  Anything involving the
>  > methods package is definitely not for R-help: I doubt if 1% of the
>  > readership of R-help have knowingly used it.
> 
> I believe the general guidelines for what goes in r-help and what in 
> r-devel are clear enough without actively discouraging discussion of 
> classes and methods.  It's the nature of the question, not a litmus test
> 
> for discussing this or that package that is the helpful distinction.
> 
> 
> ....
> 
> 
>>        if (is.primitive(baseDef)) {
>>            value <- genericForPrimitive(f)
>>
>>and it seems John Chambers has defined an S4 generic for as.character 
>>with one arg, "x".  Had he not done so it would have been (x, ...).
> 
> My 
> 
>>guess is that this is because in S the arg list is (x) and he
> 
> overlooked 
> 
>>that it was not in R, but only he knows.
> 
> 
> Well, let's say that he usually implemented the S4 generics for 
> primitives assuming R might follow the description in the Blue Book. 
> Further checking against the R online documentation was done, but 
> obviously not often enough.  Life is, however, short.
> 
> No intention to create incompatibility between the S4 generic and S3 
> code in this case, we should fix that.
> 
> There are some cases in which the generic needs extra named arguments to
> 
> allow sensible methods, for example "[".  I can't think of any case 
> where one would intentionally have _fewer_ arguments in the generic.
> 
> 
>>
>>
> ......
> 
> ______________________________________________
> R-devel@stat.math.ethz.ch mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>


[Rd] RE: [R] as.character methods
John Chambers