[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