Skip to content

Why does typeof() modify an object's "named" field?

2 messages · Josh O'Brien, R. Michael Weylandt

#
Hello,

Doing typeof() on an object appears to reset the "named" field in its
sxpinfo header to 2, which can change the way that subsequent
subassignment operations are carried out:


X <- 1:5e7
.Internal(inspect(X))
# @4eeb0008 13 INTSXP g0c7 [NAM(1)] (len=50000000, tl=0) 1,2,3,4,5,...
system.time(X[1] <- 9L)
#    user  system elapsed
#       0       0       0


typeof(X)

.Internal(inspect(X))
# @4eeb0008 13 INTSXP g1c7 [MARK,NAM(2)] (len=50000000, tl=0) 9,2,3,4,5,...
system.time(X[2] <- 9L)
#    user  system elapsed
#    0.16    0.08    0.23

Some other functions that query the nature of an object (e.g. class(),
length(), attributes()) do not modify the object's "named" field. Is
there a reason that typeof() should?


(Possibly of interest is this somewhat related thread on Stack
Overflow: http://stackoverflow.com/questions/15559387/operator-in-rstudio-and-r/15559956#15559956
).
#
On Fri, Mar 22, 2013 at 7:43 PM, Josh O'Brien <joshmobrien at gmail.com> wrote:
Because it's not implemented as a primitive and the closure used in
setting up the internal call [1] bumps up the NAMED field:

compare

x <- 1:3; y <- 1:4;  z <- 1:5

.Internal(inspect(x))
typeof(x) # Closure
.Internal(inspect(x))

.Internal(inspect(y))
class(y) # Primitive
.Internal(inspect(y))

.Internal(inspect(z))
.Internal(typeof(z))
.Internal(inspect(z))

giving
@7886c78 13 INTSXP g0c2 [NAM(1)] (len=3, tl=0) 1,2,3
[1] "integer"
@7886c78 13 INTSXP g0c2 [NAM(2)] (len=3, tl=0) 1,2,3
@7886cf0 13 INTSXP g0c2 [NAM(1)] (len=4, tl=0) 1,2,3,4
[1] "integer"
@7886cf0 13 INTSXP g0c2 [NAM(1)] (len=4, tl=0) 1,2,3,4
@7a8e9d8 13 INTSXP g0c3 [NAM(1)] (len=5, tl=0) 1,2,3,4,5
[1] "integer"
@7a8e9d8 13 INTSXP g0c3 [NAM(1)] (len=5, tl=0) 1,2,3,4,5

Michael

[1] I'm not super certain about the fact it's the closure vs argument
passing (or if the distinction even makes sense) but I know that this
behavior is part of the reason primitives are important.