[Rd] incoherent treatment of NULL
Martin Maechler
maechler at stat.math.ethz.ch
Mon Mar 23 17:33:17 CET 2009
>>>>> "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
More information about the R-devel
mailing list