Skip to content

Implementation of the names attribute of attribute lists

2 messages · Gabriel Baud-Bovy, Martin Maechler

#
Hi Martin,

Thanks for your reply. I am responding on r-devel to
provide some examples of outputs of the function that
I had list in the post-scriptum of my previous
email (BTW, did my post went through the list? I
subscribed only after mailing it).
You wrote:

            
Would printObject or printSEXP a better name?
As I wrote in my email, I might have reinvented
the wheel. I did not know str! The output of
str and print.object is quite similar for
atomic and list objects. I might look at this
function to change the argument names of the
print.object function.

However, the output of str is quite different
for language expressions and does not show as well
the their list-like strcuture since it respects
the superficial C-like syntax of the R language
(at the textual level).

In contrast, print.object prints all R objects in a much
more uniform way. For me, at least, it is both simpler because
it handles recursive R-objects with a similar
format and closer to the internal Lisp-like SEXPR
structures representing the R objects.

It has, I think, a pedagogic value in particular
for language objects and can be useful when "computing
on the language". The goal was really to be simple,
clear and close the true and elegant internal
representation of the R  objects.

Examples

Atomic object

x<-matrix(1,2,2)
dimnames(x)<-list(c("1","2"),c("a","b"))
printObject(x,print.attr=T)
- <double>=1,1,1,1
   + [[attributes]] <list>
     - [dim] <integer>=2,2
     + [dimnames] <list>
       - <character>='1','2'
       - <character>='a','b'

str(x)
  num [1:2, 1:2] 1 1 1 1
  - attr(*, "dimnames")=List of 2
   ..$ : chr [1:2] "1" "2"
   ..$ : chr [1:2] "a" "b"

Note: I have chosen not to represent the names attribute of
the attribute list since I don't know how it is internally
represented as I said in my previous email.

 > x<-list(first=pairlist(a="a",b=as.name("b")),second=2)
 > printObject(x)
+ <list>
   + [first] <pairlist>
     - [a] <character>='a'
     - [b] <symbol>=b
   - [second] <double>=2
 > str(x)
List of 2
  $ first :Dotted pair list of 2
   ..$ a: chr "a"
   ..$ b: symbol b
  $ second: num 2
 > dput(x)
structure(list(first = list(a = "a", b = b), second = 2), .Names = c("first",
"second"))

Closure example

foo<-function(x,y)x+y
printObject(foo)
+ <closure>
   + [[formals]] <pairlist>
     - [x] <symbol>=''
     - [y] <symbol>=''
   + [[body]] <language>
     - <symbol>=+
     - <symbol>=x
     - <symbol>=y
   + [[env]] <environment>=<environment: R_GlobalEnv>


str(foo)
function (x, y)
  - attr(*, "source")= chr "function(x,y)x+ydput(foo)

dput(foo)
function (x, y)
x + y

Function calls:

printObject(quote(2+2))
+ <language>
   - <symbol>=+
   - <double>=2
   - <double>=2

printObject(expression(2+2))
+ <expression>
   + <language>
     - <symbol>=+
     - <double>=2
     - <double>=2
dput(expression(2+2))
expression(2 + 2)

printObject(quote(expression(2+2)))
+ <language>
   - <symbol>=expression
   + <language>
     - <symbol>=+
     - <double>=2
     - <double>=2
dput(quote(expression(2+2)))
expression(2 + 2)

statement<-quote(function(x,y){z<-(x+y)/2;z})
printObject(statement)
+ <language>
   - <symbol>=function
   + <pairlist>
     - [x] <symbol>=''
     - [y] <symbol>=''
   + <language>
     - <symbol>={
     + <language>
       - <symbol>=<-
       - <symbol>=z
       + <language>
         - <symbol>=/
         + <language>
           - <symbol>=(
           + <language>
             - <symbol>=+
             - <symbol>=x
             - <symbol>=y
         - <double>=2
     - <symbol>=z
   - <character>='function(x,y){z<-(x+y)/2;z}'

dput(statement)
function(x, y) {
     z <- (x + y)/2
     z
}

The output of printObject makes it easy to
identify and eventually change an element
of an expression (it easy to count the
argument in each function call).
For eample, to replace a division by
a multiplication

statement[[3]][[2]][[3]][[1]]<-as.name("*")


One additional point, to wrap the names of the elements of
recursive objects, I have used double brackets [[]] to
distinguish between a SEXP inside the SEXPR (this also used
for attributes) and single brackects for generic vectors.
For pairlist, I also use single brackets because it
is writtin in the Manual that they are converted in
generic vector of type pairlist when accessed from R.

The print.object function allows also to use the
"typefun" function (but this is a detail).

Regards,

Gabriel
--------------------------------------------------------------------
Gabriel Baud-Bovy                            tel: (+39) 02 2643 4839
Faculty of Psychology, UHSR University       fax: (+39) 02 2643 4892
via Olgettina, 58, 20132 Milan, Italy
#
Gabriel> Hi Martin,
    Gabriel> Thanks for your reply. I am responding on r-devel to
    Gabriel> provide some examples of outputs of the function that
    Gabriel> I had list in the post-scriptum of my previous
    Gabriel> email (BTW, did my post went through the list? I
    Gabriel> subscribed only after mailing it).
Gabriel> You wrote:
>> Just to ask the obvious:
    >> 
    >> Why is using  str() not sufficient for you and instead,
    >> you use  'print.object' {not a good name, BTW, since it looks like a
    >> print() S3 method but isn't one} ?

    Gabriel> Would printObject or printSEXP a better name?

definitely better because not interfering with the S3 pseudo-OO convention...
Still not my taste though :   
      every R object is an object (:-) -- and a SEXP internally --
      and we don't use 'fooObject' for other function names even
      though their arguments are R objects....
My taste would rather lead to something like
 'displayStructure' (or 'dissectInternal' ;-) or a shorter
version of those.

    >> The very few cases I found it was insufficient,
    >> certainly  dput()  was, possibly even using it as
    >> dput(. , control = ....).

    Gabriel> As I wrote in my email, I might have reinvented
    Gabriel> the wheel. I did not know str! 

(amazingly ... ;-)

    Gabriel> The output of str and print.object is quite similar
    Gabriel> for atomic and list objects. I might look at this
    Gabriel> function to change the argument names of the
    Gabriel> print.object function.

    Gabriel> However, the output of str is quite different
    Gabriel> for language expressions and does not show as well
    Gabriel> the their list-like strcuture since it respects
    Gabriel> the superficial C-like syntax of the R language
    Gabriel> (at the textual level).

Ok, thanks for clarifying this aspect, and the difference to
both str() and dput() here.

    <.... much omitted ...>

Martin Maechler,
ETH Zurich