[Rd] Implementation of the names attribute of attribute lists
Gabriel Baud-Bovy
baud-bovy.gabriel at hsr.it
Tue May 10 13:46:52 CEST 2005
Dear all,
Internally, the attribute list appears to be implemented as an generic
list vector with a names attributes (i.e., the attribute slot in the object's
SEXPREC structure would point toward a VECTOR_SEXPREC representing
a generic vector).
> attributes(c(a=1))
$names
[1] "a"
> typeof(attributes(c(a=1)))
[1] "list"
From R, it appears as if the named list had itself an
named attributes list and so on .... until no end
> attributes(attributes(c(a=1)))
$names
[1] "names"
> attributes(attributes(attributes(c(a=1))))
$names
[1] "names"
Etc.
This is also the case for any object having an attributes list.
> attributes(matrix(1,1,1))
$dim
[1] 1 1
> attributes(attributes(matrix(1,1,1)))
$names
[1] "dim"
> attributes(attributes(attributes(matrix(1,1,1))))
$names
[1] "names"
Obviously, this behavior of the attributes function cannot reflect the
actual internal structure of the object. My question is therefore
whether named lists used as attribute have themselves a names attribute?
Another possibility would be that the names attribute of an attribute list
does not have a names attribute. A final possibility might be that
attribute list are implemented with dotted lists (pairlists) and
that the behaviour attributes reflect pairlist's "virtual" names
attributes. In this case, however, one would have expected
typeof(attributes(attributes(c(a=1))))
[1] "list"
to return "pairlist".
Could you reply to me on my private address? Thank you a lot.
Gabriel
PS: I wrote a function that prints the list-like internal structure
of any R object (this is quite easy indeed :-)) and wrote the draft
of an article documenting it that I am thinking of submitting to
R-news. I would however appreciate your feedback on it (did I reinvent
the wheel?). This function, I think, could be used in many places
to document apparently obscure or confusing aspects of the R
language to a non-expert user. It is also quite useful when "computing
on the language".
## The print.object function prints a tree representing the list-like structure
## of any R object
##
## x: any R object
## typefun: anfunction returning the object's type (e.g., mode,
storage.mode, class)
## print.attributes: flag indicating whether to print or not the attributes
list
## deparse.level: the printout beyond this level is produced by the deparse
function
##
## The name and level arguments are not intended to be used at the user-level.
print.object<-function(x,typefun=typeof,print.attributes=F,deparse.level=Inf,name=NULL,level=0)
{
margin<-paste(rep(" ",level),collapse="")
# tag contain the name of the object (if any)
tag<-if(!is.null(name)) paste("[",name,"] ",sep="") else ""
#
if(level>=deparse.level) {
# if level exceeds maximum, simplify output by using
deparse function
cat(margin,"+ ",tag,"deparse :
",paste(deparse(x),collapse=""),"\n",sep="")
} else if(is.element(typeof(x),c("environment","promise"))) {
# environment and promises are recusive objects that
cannot be transformed
# into list
cat(margin,"+ ",tag,"<",typefun(x),">=",sep="")
print(x)
} else if(typeof(x)=="closure") {
cat(margin,"+ ",tag,"<",typefun(x),">\n",sep="")
# print each part (formals, body and environment) of a
function object separately
print.object(formals(x),typefun,print.attributes,deparse.level,"[formals]",level+1)
print.object(body(x),typefun,print.attributes,deparse.level,"[body]",level+1)
print.object(environment(x),typefun,print.attributes,deparse.level,"[env]",level+1)
} else if(is.recursive(x)) {
# print type of the recursive object (as determined by
typefun function)
cat(margin,"+ ",tag,"<",typefun(x),">\n",sep="")
# loop to print each element of the recursive object
# note: element's name is transmitted separetely (NULL if
absent)
xx<-as.list(x)
for(i in seq(along=xx))
print.object(xx[[i]],typefun,print.attributes,deparse.level,names(xx)[i],level+1)
} else {
# print atomic objects (vector, matrices, etc)
aux<-switch(as.character(mode(x)),
"character"=paste("\'",x,"\'",sep=""), # add
quotes to characters
"NULL"="NULL",
as.character(x))
aux<-paste(aux,collapse=",")
if(nchar(aux)==0)aux<-"\'\'" # occurs in case of formals
without default value in a function definition
cat(margin,"- ",tag,"<", typefun(x),">=",aux,sep="")
# names are also printed if they exist
if(!is.null(names(x))) cat(" [names]=",
paste("\'",names(x),"\'",sep="",collapse=","),sep="")
cat("\n")
}
# print attributes (if any)
if(print.attributes && !is.null(attributes(x))) {
# note: attributes are contained in a named list. Infinite
recursion
# can happen because attributes lists have themselves a
"names" attribute.
if(!is.null(name) && name=="[attributes]") {
# print the names attribute of the attribute list
# cat(margin," ","+
","[[attributes]]","<list>\n",sep="")
# cat(margin," "," ","-
","[names]",paste("\'",names(x),"\'",sep="",collapse=","),"\n",sep="")
return(invisible(NULL)) # prevent infinite recursion
}
# print attriutes list
print.object(attributes(x),typefun,print.attributes,deparse.level,"[attributes]",level+1)
}
invisible(NULL)
}
--------------------------------------------------------------------
Gabriel Baud-Bovy tel: (+39) 02 2643 4839
Faculty of Psychology, UHSR University fax: (+39) 02 2643 4892
via Olgettina, 58, 20132 Milan, Italy
More information about the R-devel
mailing list