From jmc at r-project.org  Sun Apr 22 00:08:14 2007
From: jmc at r-project.org (John Chambers)
Date: Sat, 21 Apr 2007 15:08:14 -0700
Subject: [Rd] infinite recursion when printing former S4 objects
In-Reply-To: <m2ps5zlykg.fsf@ziti.local>
References: <m2ps5zlykg.fsf@ziti.local>
Message-ID: <462A8B4E.9000101@r-project.org>

Classes that contain "matrix" are trouble.  Matrix objects are, well, 
weird.  They look like they should be S3 classes but the object bit is 
not turned on and they have no class attribute.   They seem to be 
recognized by much internal code on the basis of the "dim" attribute, so 
they appear to dispatch S3 methods, for example.

They've been allowed as a data part in S4 class definitions, but it 
seems that we should perhaps retract that, unless it can be made to work 
reliably, which may not be possible without changing the semantics of 
matrix objects.

The problems with class "Foo" are not just with printing.  For example:

 > setClass("Foo", representation(name="character"), contains="matrix")
[1] "Foo"
 > x = new("Foo", 1:12)
Error: evaluation nested too deeply: infinite recursion / 
options(expressions=)?

A little investigation pins this one down to as(x, "vector") <-

Aside from these really nasty features, there is a problem with 
containing S3 classes in general, because the S3 dispatch can't 
recognize the new class as inheriting from the S3 class.  For example:

 > bar = function(x)UseMethod("bar")
 > bar.matrix = function(x)"Matrix bar"
 > mm = matrix(1:12,3,4)
 > bar(mm)
[1] "Matrix bar"
 > mF = new("Foo", mm)
 > bar(mF)
Error in bar(mF) : no applicable method for "bar"
 > is.matrix(mF)
[1] TRUE

I do agree that the S4 bit should be turned off when an object drops 
down to having no class--it's something that doesn't seem to cause the 
same problems with inheritance from other basic data classes, though:

 > setClass("c2", representation(name = "character"), contains = "numeric")
[1] "c2"
 > cc = new("c2", 1:12)
 > as(cc, "numeric")
 [1]  1  2  3  4  5  6  7  8  9 10 11 12
 > cn = as(cc,"numeric")
 > class(cn)
[1] "integer"
 > attr(cn, "class")
NULL
 > isS4(cn)
[1] TRUE
 > print(cn)
 [1]  1  2  3  4  5  6  7  8  9 10 11 12

John

Seth Falcon wrote:
> Hello all,
>
> An S4 class that contains matrix can be converted into a matrix using
> as().  When the resulting object is printed implicitly at the command
> line, all is well.  When print() is explicitly called, I see an
> infinite recursion.
>
> Here is an example:
>
> ## create a subclass of matrix
>     > setClass("Foo", representation(name="character"), contains="matrix")
>     [1] "Foo"
>
> ## test it out
>     > f <- new("Foo", name="Sam", matrix())
>     > z <- as(f, "matrix")
>     > z
>          [,1]
>     [1,]   NA
>     > print(z)
>     Error: evaluation nested too deeply: infinite recursion / options(expressions=)?
>
> An easy cut/paste version is below.  I'm seeing this with an R 2.5.0
> beta.  I noticed that isS4(z) returns TRUE.  This may or may not be
> surprising, but seems quite related to the issue at hand.
>
>
> + seth
>
>
>
> ## ----------------8<--------------8<-----------------------
>
> setClass("Foo", representation(name="character"), contains="matrix")
> f <- new("Foo", name="Sam", matrix())
> f
> m <- as(f, "matrix")
> m
> print(m)
>
> ## ----------------8<--------------8<-----------------------
>
>
>



[Rd] infinite recursion when printing former S4 objects
John Chambers