somewhat related to a previous discussion [1] on how 'names<-' would
sometimes modify its argument in place, and sometimes produce a modified
copy without changing the original, here's another example of how it
becomes visible to the user when r makes or doesn't make a copy of an
object:
x = NULL
dput(x)
# NULL
class(x) = 'integer'
# error: invalid (NULL) left side of assignment
x = c()
dput(x)
# NULL
class(x) = 'integer'
dput(x)
# integer(0)
in both cases, x ends up with the value NULL (the no-value object). in
both cases, dput explains that x is NULL. in both cases, an attempt is
made to make x be an empty integer vector. the first fails, because it
tries to modify NULL itself, the latter apparently does not and succeeds.
however, the following has a different pattern:
x = NULL
dput(x)
# NULL
names(x) = character(0)
# error: attempt to set an attribute on NULL
x = c()
dput(x)
# NULL
names(x) = character(0)
# error: attempt to set an attribute on NULL
and also:
x = c()
class(x) = 'integer'
# fine
class(x) = 'foo'
# error: attempt to set an attribute on NULL
how come? the behaviour can obviously be explained by looking at the
source code (hardly surprisingly, because it is as it is because the
source is as it is), and referring to the NAMED property (i.e., the
sxpinfo.named field of a SEXPREC struct). but can the *design* be
justified? can the apparent incoherences visible above the interface be
defended?
why should the first example above be unable to produce an empty integer
vector?
why is it possible to set a class attribute, but not a names attribute,
on c()?
why is it possible to set the class attribute in c() to 'integer', but
not to 'foo'?
why are there different error messages for apparently the same problem?
vQ
[1] search the rd archives for 'surprising behaviour of names<-'
incoherent treatment of NULL
7 messages · Wacek Kusnierczyk, Martin Maechler
"WK" == Wacek Kusnierczyk <Waclaw.Marcin.Kusnierczyk at idi.ntnu.no>
on Mon, 23 Mar 2009 09:52:19 +0100 writes:
WK> somewhat related to a previous discussion [1] on how 'names<-' would
WK> sometimes modify its argument in place, and sometimes produce a modified
WK> copy without changing the original, here's another example of how it
WK> becomes visible to the user when r makes or doesn't make a copy of an
WK> object:
WK> x = NULL
WK> dput(x)
WK> # NULL
WK> class(x) = 'integer'
WK> # error: invalid (NULL) left side of assignment
does not happen for me in R-2.8.1, R-patched or newer
So you must be using your own patched version of R ?
????
WK> x = c()
WK> dput(x)
WK> # NULL
WK> class(x) = 'integer'
WK> dput(x)
WK> # integer(0)
WK> in both cases, x ends up with the value NULL (the no-value object). in
WK> both cases, dput explains that x is NULL. in both cases, an attempt is
WK> made to make x be an empty integer vector. the first fails, because it
WK> tries to modify NULL itself, the latter apparently does not and succeeds.
WK> however, the following has a different pattern:
WK> x = NULL
WK> dput(x)
WK> # NULL
WK> names(x) = character(0)
WK> # error: attempt to set an attribute on NULL
WK> x = c()
WK> dput(x)
WK> # NULL
WK> names(x) = character(0)
WK> # error: attempt to set an attribute on NULL
WK> and also:
WK> x = c()
WK> class(x) = 'integer'
WK> # fine
WK> class(x) = 'foo'
WK> # error: attempt to set an attribute on NULL
WK> how come? the behaviour can obviously be explained by looking at the
WK> source code (hardly surprisingly, because it is as it is because the
WK> source is as it is), and referring to the NAMED property (i.e., the
WK> sxpinfo.named field of a SEXPREC struct). but can the *design* be
WK> justified? can the apparent incoherences visible above the interface be
WK> defended?
WK> why should the first example above be unable to produce an empty integer
WK> vector?
WK> why is it possible to set a class attribute, but not a names attribute,
WK> on c()?
WK> why is it possible to set the class attribute in c() to 'integer', but
WK> not to 'foo'?
WK> why are there different error messages for apparently the same problem?
WK> vQ
WK> [1] search the rd archives for 'surprising behaviour of names<-'
WK> ______________________________________________
WK> R-devel at r-project.org mailing list
WK> https://stat.ethz.ch/mailman/listinfo/r-devel
Martin Maechler wrote:
"WK" == Wacek Kusnierczyk <Waclaw.Marcin.Kusnierczyk at idi.ntnu.no>
WK> somewhat related to a previous discussion [1] on how 'names<-' would
WK> sometimes modify its argument in place, and sometimes produce a modified
WK> copy without changing the original, here's another example of how it
WK> becomes visible to the user when r makes or doesn't make a copy of an
WK> object:
WK> x = NULL
WK> dput(x)
WK> # NULL
WK> class(x) = 'integer'
WK> # error: invalid (NULL) left side of assignment
does not happen for me in R-2.8.1, R-patched or newer
So you must be using your own patched version of R ?
oops, i meant to use 2.8.1 or devel for testing. you're right, in this example there is no error reported in > 2.8.0, but see below.
WK> x = c()
WK> dput(x)
WK> # NULL
WK> class(x) = 'integer'
WK> dput(x)
WK> # integer(0)
WK> in both cases, x ends up with the value NULL (the no-value object). in
WK> both cases, dput explains that x is NULL. in both cases, an attempt is
WK> made to make x be an empty integer vector. the first fails, because it
WK> tries to modify NULL itself, the latter apparently does not and succeeds.
WK> however, the following has a different pattern:
WK> x = NULL
WK> dput(x)
WK> # NULL
WK> names(x) = character(0)
WK> # error: attempt to set an attribute on NULL
i get the error in devel.
WK> x = c()
WK> dput(x)
WK> # NULL
WK> names(x) = character(0)
WK> # error: attempt to set an attribute on NULL
i get the error in devel.
WK> and also:
WK> x = c()
WK> class(x) = 'integer'
WK> # fine
WK> class(x) = 'foo'
WK> # error: attempt to set an attribute on NULL
i get the error in devel.
it doesn't seem coherent to me: why can i set the class, but not names
attribute on both NULL and c()? why can i set the class attribute to
'integer', but not to 'foo', as i could on a non-empty vector:
x = 1
class(x) = 'foo'
# just fine
i'd naively expect to be able to create an empty vector classed 'foo',
displayed perhaps as
# speculation
x = NULL
class(x) = 'foo'
x
# foo(0)
or maybe as
x
# NULL
# attr(, "class")
# [1] "foo"
vQ
"WK" == Wacek Kusnierczyk <Waclaw.Marcin.Kusnierczyk at idi.ntnu.no>
on Mon, 23 Mar 2009 10:56:37 +0100 writes:
WK> Martin Maechler wrote:
>>>>>>> "WK" == Wacek Kusnierczyk <Waclaw.Marcin.Kusnierczyk at idi.ntnu.no>
>>>>>>>
>>>>>>>
WK> somewhat related to a previous discussion [1] on how 'names<-' would
WK> sometimes modify its argument in place, and sometimes produce a modified
WK> copy without changing the original, here's another example of how it
WK> becomes visible to the user when r makes or doesn't make a copy of an
WK> object:
>>
WK> x = NULL
WK> dput(x)
WK> # NULL
WK> class(x) = 'integer'
WK> # error: invalid (NULL) left side of assignment
>>
>> does not happen for me in R-2.8.1, R-patched or newer
>>
>> So you must be using your own patched version of R ?
>>
WK> oops, i meant to use 2.8.1 or devel for testing. you're right, in this
WK> example there is no error reported in > 2.8.0, but see below.
ok
[...... omitted part no longer relevant ........]
WK> however, the following has a different pattern:
>>
WK> x = NULL
WK> dput(x)
WK> # NULL
WK> names(x) = character(0)
WK> # error: attempt to set an attribute on NULL
>>
WK> i get the error in devel.
Yes, NULL is NULL is NULL ! Do read ?NULL ! [ ;-) ]
more verbously, all NULL objects in R are identical, or as the
help page says, there's only ``*The* NULL Object'' in R,
i.e., NULL cannot get any attributes.
WK> x = c()
WK> dput(x)
WK> # NULL
WK> names(x) = character(0)
WK> # error: attempt to set an attribute on NULL
>>
WK> i get the error in devel.
of course!
[I think *you* should have noticed that NULL and c() *are* identical]
WK> and also:
>>
WK> x = c()
WK> class(x) = 'integer'
WK> # fine
"fine" yes;
here, the convention has been to change NULL into integer(0);
and no, this won't change, if you find it inconsistent.
WK> class(x) = 'foo'
WK> # error: attempt to set an attribute on NULL
>>
WK> i get the error in devel.
No, not if you evaluate the statements above (where 'x' has
become 'integer(0)' in the mean time).
But yes, you get in something like
x <- c(); class(x) <- "foo"
and I do agree that there's a buglet :
The error message should be slightly more precise,
--- improvement proposals are welcome ---
but an error nontheless
WK> it doesn't seem coherent to me: why can i set the class,
you cannot set it, you can *change* it.
WK> but not names
WK> attribute on both NULL and c()? why can i set the class attribute to
WK> 'integer', but not to 'foo', as i could on a non-empty vector:
WK> x = 1
WK> class(x) = 'foo'
WK> # just fine
mainly because 'NULL is NULL is NULL'
(NULL cannot have attributes)
WK> i'd naively expect to be able to create an empty vector classed 'foo',
yes, but that expectation is wrong
WK> displayed perhaps as
WK> # speculation
WK> x = NULL
WK> class(x) = 'foo'
WK> x
WK> # foo(0)
WK> or maybe as
WK> x
WK> # NULL
WK> # attr(, "class")
WK> # [1] "foo"
WK> vQ
WK> ______________________________________________
WK> R-devel at r-project.org mailing list
WK> https://stat.ethz.ch/mailman/listinfo/r-devel
Martin Maechler wrote:
[...... omitted part no longer relevant ........]
WK> however, the following has a different pattern:
>>
WK> x = NULL
WK> dput(x)
WK> # NULL
WK> names(x) = character(0)
WK> # error: attempt to set an attribute on NULL
>>
WK> i get the error in devel.
Yes, NULL is NULL is NULL ! Do read ?NULL ! [ ;-) ]
more verbously, all NULL objects in R are identical, or as the
help page says, there's only ``*The* NULL Object'' in R,
i.e., NULL cannot get any attributes.
yes, but that's not the issue. the issue is that names(x)<- seems to
try to attach an attribute to NULL, while it could, in principle, do the
same as class(x)<-, i.e., coerce x to some type (and hence attach the
name attribute not to NULL, but to the coerced-to object).
but, as someone else explained to me behind the scenes, the matters are
a little bit, so to speak, untidy:
x = NULL
class(x) = 'integer'
# just fine
x = NULL
attr(x, 'class') = 'integer'
# no go
where class()<-, but not attr(,'class')<-, will try to coerce x to an
object of the storage *mode* 'integer', hence the former succeeds
(because it sets, roughly, the 'integer' class on an empty integer
vector), while the latter fails (because it tries to set the 'integer'
class on NULL itself).
what was not clear to me is not why setting a class on NULL fails here,
but why it is setting on NULL in the first place. after all,
x = 1
names(x) = 'foo'
is setting names on a *copy* of 1, not on *the* 1, so why could not
class()<- create a 'copy' of NULL, i.e., an empty vector of some type
(perhaps raw, as the lowest in the hierarchy).
WK> x = c()
WK> dput(x)
WK> # NULL
WK> names(x) = character(0)
WK> # error: attempt to set an attribute on NULL
>>
WK> i get the error in devel.
of course!
[I think *you* should have noticed that NULL and c() *are* identical]
WK> and also:
>>
WK> x = c()
WK> class(x) = 'integer'
WK> # fine
"fine" yes;
here, the convention has been to change NULL into integer(0);
and no, this won't change, if you find it inconsistent.
that's ok, this is what i'd expect in the other cases, too (modulo the actual storage mode).
WK> class(x) = 'foo'
WK> # error: attempt to set an attribute on NULL
>>
WK> i get the error in devel.
No, not if you evaluate the statements above (where 'x' has
become 'integer(0)' in the mean time).
But yes, you get in something like
x <- c(); class(x) <- "foo"
that's what i meant, must have forgotten the x = c().
and I do agree that there's a buglet :
The error message should be slightly more precise,
--- improvement proposals are welcome ---
but an error nontheless
WK> it doesn't seem coherent to me: why can i set the class,
you cannot set it, you can *change* it.
terminological wars?
btw. the class of NULL is "NULL"; why can't nullify an object by
setting its class to 'NULL'?
x = 1
class(x) = 'NULL'
x
# *not* NULL
and one more interesting example:
x = 1:2
class(x) = 'NULL'
x
# [1] 1 2
# attr(,"class") "NULL"
x[1]
# 1
x[2]
# 2
is.vector(x)
# FALSE
hurray!!! apparently, i've alchemized a non-vector vector... (you can
do it in r-devel, for that matter).
WK> but not names
WK> attribute on both NULL and c()? why can i set the class attribute to
WK> 'integer', but not to 'foo', as i could on a non-empty vector:
WK> x = 1
WK> class(x) = 'foo'
WK> # just fine
mainly because 'NULL is NULL is NULL'
(NULL cannot have attributes)
yes yes yes; the question was, once again: why is x still NULL?
WK> i'd naively expect to be able to create an empty vector classed 'foo', yes, but that expectation is wrong
wrt. the actual state of matters, not necessarily wrt. the ideal state of matters ;) (i don't insist) vQ
"WK" == Wacek Kusnierczyk <Waclaw.Marcin.Kusnierczyk at idi.ntnu.no>
on Mon, 23 Mar 2009 16:11:04 +0100 writes:
WK> Martin Maechler wrote:
>>
>> [...... omitted part no longer relevant ........]
>>
WK> however, the following has a different pattern:
>> >>
WK> x = NULL
WK> dput(x)
WK> # NULL
WK> names(x) = character(0)
WK> # error: attempt to set an attribute on NULL
>> >>
>>
WK> i get the error in devel.
>>
>> Yes, NULL is NULL is NULL ! Do read ?NULL ! [ ;-) ]
>>
>> more verbously, all NULL objects in R are identical, or as the
>> help page says, there's only ``*The* NULL Object'' in R,
>> i.e., NULL cannot get any attributes.
>>
WK> yes, but that's not the issue. the issue is that names(x)<- seems to
WK> try to attach an attribute to NULL, while it could, in principle, do the
WK> same as class(x)<-, i.e., coerce x to some type (and hence attach the
WK> name attribute not to NULL, but to the coerced-to object).
yes, it could; but really, the fact that 'class<-' works is
the exception. The other variants (with the error message) are
the rule.
WK> but, as someone else explained to me behind the scenes, the matters are
WK> a little bit, so to speak, untidy:
WK> x = NULL
WK> class(x) = 'integer'
WK> # just fine
WK> x = NULL
WK> attr(x, 'class') = 'integer'
WK> # no go
WK> where class()<-, but not attr(,'class')<-, will try to coerce x to an
WK> object of the storage *mode* 'integer', hence the former succeeds
WK> (because it sets, roughly, the 'integer' class on an empty integer
WK> vector), while the latter fails (because it tries to set the 'integer'
WK> class on NULL itself).
WK> what was not clear to me is not why setting a class on NULL fails here,
WK> but why it is setting on NULL in the first place. after all,
WK> x = 1
WK> names(x) = 'foo'
WK> is setting names on a *copy* of 1, not on *the* 1, so why could not
WK> class()<- create a 'copy' of NULL, i.e., an empty vector of some type
WK> (perhaps raw, as the lowest in the hierarchy).
yes, it could. I personally don't think this would add any
value to R's behavior; rather, for most useRs I'd think it
rather helps to get an error in such a case, than a raw(0)
object.
Also, note (here and further below),
that Using "class(.) <- <className>"
is an S3 idiom and S3 classes ``don't really exist'',
the "class" attribute being a useful hack,
and many of us would rather like to work and improve working
with S4 classes (& generics & methods) than to fiddle with 'class<-'.
In S4, you'd use setClass(.), new(.) and setAs(.),
typically, for defining and changing classes of objects.
But maybe I have now lead you into a direction I will later
regret,
....
when you start telling us about the perceived inconsistencies of
S4 classes, methods, etc.
BTW: If you go there, please do use R 2.9.0 (or newer)
exclusively.
WK> x = c()
WK> dput(x)
WK> # NULL
WK> names(x) = character(0)
WK> # error: attempt to set an attribute on NULL
>> >>
>>
WK> i get the error in devel.
>>
>> of course!
>> [I think *you* should have noticed that NULL and c() *are* identical]
>>
WK> and also:
>> >>
WK> x = c()
WK> class(x) = 'integer'
WK> # fine
>> "fine" yes;
>> here, the convention has been to change NULL into integer(0);
>> and no, this won't change, if you find it inconsistent.
>>
WK> that's ok, this is what i'd expect in the other cases, too (modulo the
WK> actual storage mode).
>>
WK> class(x) = 'foo'
WK> # error: attempt to set an attribute on NULL
>> >>
>>
WK> i get the error in devel.
>>
>> No, not if you evaluate the statements above (where 'x' has
>> become 'integer(0)' in the mean time).
>>
>> But yes, you get in something like
>>
>> x <- c(); class(x) <- "foo"
>>
WK> that's what i meant, must have forgotten the x = c().
>> and I do agree that there's a buglet :
>> The error message should be slightly more precise,
>> --- improvement proposals are welcome ---
>> but an error nontheless
>>
WK> it doesn't seem coherent to me: why can i set the class,
>>
>> you cannot set it, you can *change* it.
>>
WK> terminological wars?
WK> btw. the class of NULL is "NULL"; why can't nullify an object by
WK> setting its class to 'NULL'?
WK> x = 1
WK> class(x) = 'NULL'
WK> x
WK> # *not* NULL
see above {S4 / S3 / ...};
If you want to "nullify", rather use
more (S-language) idiomatic calls like
as(x, "NULL")
or
as.null(x)
both of which do work.
Regards,
Martin
WK> and one more interesting example:
WK> x = 1:2
WK> class(x) = 'NULL'
WK> x
WK> # [1] 1 2
WK> # attr(,"class") "NULL"
WK> x[1]
WK> # 1
WK> x[2]
WK> # 2
WK> is.vector(x)
WK> # FALSE
WK> hurray!!! apparently, i've alchemized a non-vector vector... (you can
WK> do it in r-devel, for that matter).
WK> but not names
WK> attribute on both NULL and c()? why can i set the class attribute to
WK> 'integer', but not to 'foo', as i could on a non-empty vector:
>>
WK> x = 1
WK> class(x) = 'foo'
WK> # just fine
>>
>> mainly because 'NULL is NULL is NULL'
>> (NULL cannot have attributes)
>>
WK> yes yes yes; the question was, once again: why is x still NULL?
WK> i'd naively expect to be able to create an empty vector classed 'foo',
>>
>> yes, but that expectation is wrong
>>
WK> wrt. the actual state of matters, not necessarily wrt. the ideal state
WK> of matters ;) (i don't insist)
WK> vQ
Martin Maechler wrote:
>> more verbously, all NULL objects in R are identical, or as the
>> help page says, there's only ``*The* NULL Object'' in R,
>> i.e., NULL cannot get any attributes.
>>
WK> yes, but that's not the issue. the issue is that names(x)<- seems to
WK> try to attach an attribute to NULL, while it could, in principle, do the
WK> same as class(x)<-, i.e., coerce x to some type (and hence attach the
WK> name attribute not to NULL, but to the coerced-to object).
yes, it could; but really, the fact that 'class<-' works is
the exception. The other variants (with the error message) are
the rule.
ok.
Also, note (here and further below), that Using "class(.) <- <className>" is an S3 idiom and S3 classes ``don't really exist'', the "class" attribute being a useful hack, and many of us would rather like to work and improve working with S4 classes (& generics & methods) than to fiddle with 'class<-'. In S4, you'd use setClass(.), new(.) and setAs(.), typically, for defining and changing classes of objects. But maybe I have now lead you into a direction I will later regret, .... when you start telling us about the perceived inconsistencies of S4 classes, methods, etc. BTW: If you go there, please do use R 2.9.0 (or newer)
using latest r-devel for the most part. i think you will probably not regret your words; from what i've seen already, s4 classes are the last thing i'd ever try to learn in r. but yes, there would certainly be lots of issues to complain about. i'll rather wait for s5. regards, vQ