What is the difference between NULL and character(0) in R? - r

What is the difference between NULL and character(0) | integer(0) etc?
> identical(NULL, character(0))
[1] FALSE
> is.null(integer(0))
[1] FALSE
> str(character(0))
chr(0)
> str(NULL)
NULL
In general it seems you can pass NULL as parameters into functions, and that an empty vector is generally returned as character(0), integer(0), etc.
Why is this the case? Come to think of it, is there a test for zero-ness, a la is.integer0?

The R Language Definition has this on NULL:
There is a special object called NULL. It is used whenever there is a need to indicate or
specify that an object is absent. It should not be confused with a vector or list of zero
length. The NULL object has no type and no modifiable properties. There is only one NULL
object in R, to which all instances refer. To test for NULL use is.null. You cannot set
attributes on NULL.
So by definition NULL is very different to zero length vectors. A zero length vector very much isn't absent. NULL is really a catch-all for something that is absent or not set, but not missing-ness, which is the job of NA. There is an exception, the zero-length pairlist, as mentioned by #Owen. The Language Definition states:
A zero-length pairlist is NULL, as would be expected in Lisp but in contrast to a zero-length list.
which highlights the exception in this case.
To test for a zero-length vector use something like if(length(foo) == 0L) for example. And combine that with a class check (is.character(foo)) if you want a specific type of zero length vector.

The other guys have the right answers, but I want to add a few curiosities.
First, it's not quite true that NULL "is used whenever there is a need to indicate or specify that an object is absent" as it says in the doc. There are actually 2 other "no data" values in R (not counting NA, which is not a complete value).
There's "missing", which is used for missing arguments:
alist(x=)$x
> identical(NULL, alist(x=)$x)
[1] FALSE
> y = alist(x=)$x
> y
Error: argument "y" is missing, with no default
Then there's "unbound", which you can't (AFAIK) access directly, but using C:
SEXP getUnbound(void) {
return R_UnboundValue;
}
> x = .Call("getUnbound")
> x
Error: object 'x' not found

Here's a partial answer, beginning by simply quoting the R Language Definition Guide:
There is a special object called NULL. It is used whenever there is a
need to indicate or specify that an object is absent. It should not be
confused with a vector or list of zero length. The NULL object has no
type and no modifiable properties. There is only one NULL object in R,
to which all instances refer. To test for NULL use is.null. You cannot
set attributes on NULL.
I take that to mean that zero length vectors can have attributes, whereas NULL cannot:
> x <- character(0)
> y <- NULL
> attr(x,"name") <- "nm"
> attr(y,"name") <- "nm"
Error in attr(y, "name") <- "nm" : attempt to set an attribute on NULL

Related

Why does attribute on a numeric object return NULL?

> y <- 1
> attributes(y)
NULL
While class(y) returns numeric and we know that class is an attribute, then why does attributes(y) return NULL?
R has many attributes, see ?attributes:
Note that some attributes (namely class, comment, dim, dimnames, names, row.names and tsp)...
meaning attributes is just one of the bunch. It would be erroneous to expect each object has an attributes (attributes(obj) <- value) assigned by default.

R: How do you pass the value of an expression to a function that rejects an expression argument?

MY code, below, now fixed, suffered from a different defect than I thought, unrelated to my title question. The real problem, and its solution, was supplied by #Roland, below.
I have a pair of functions, shown below, which together are supposed to return a list of the values of the column attribute named in attrC. When run, R objects that " Error in attr(x, which = get("attrC"), exact = TRUE): 'which' must be of mode character".
I have tried replacing attrC with get("attrC") and eval(attrC). Neither works.
I have three closely related questions. A good answer would answer all three.
How do I make this particular function work?
How can I tell, from the form of an R function or its documentation, when an argument which is required to be of a given type will accept a variable or expression that evaluates to that type?
If the answer to (1.) has not already supplied it: Is there a generic way to provide a function that requires an argument of given type and does not accept a name or expression which evaluates to that type, with the value from such a name or expression.
.
ColAttr <- function(x, attrC, ifIsNull) {
# Returns column attribute named in attrC, if present, else isNullC.
atr <- attr(x, attrC, exact = TRUE)
atr <- if (is.null(atr)) {ifIsNull} else {atr}
atr
}
AtribLst <- function(df, attrC, isNullC){
# Returns list of values of the col attribute attrC, if present, else isNullC
lapply(df, ColAttr, attrC=attrC, ifIsNull=isNullC)
}
stub93 <- AtribLst(cps_00093.df, attrC="label", isNullC=NA)

R function-- the default value does not work?

I am really new to R. Allow me to ask a beginner's question.
When I type p.adjust, for example, I can see the following. It seems that the argument method is p.adjust.methods by default. I tried to trace the code but when I typed something like:
match.arg(p.adjust.methods)
It says:
Error in match.arg(p.adjust.methods) : 'arg' must be of length 1
Why?
> p.adjust
function (p, method = p.adjust.methods, n = length(p))
{
method <- match.arg(method)
...
}
The match.arg function does not work in interactive mode in its one argument form, since there is nothing to match to. That first argument is expected to be a length 1 character vector, and it is tested against the known methods _inside_the_function_:
> ?p.adjust
> p.adjust.methods
[1] "holm" "hochberg" "hommel" "bonferroni" "BH" "BY" "fdr"
[8] "none"
(The first argument to p.adjust if you are using positional matching needs to be a vector of p-values.)

Error in if/while (condition) { : argument is of length zero

I received the error
Error in if (condition) { : argument is of length zero
or
Error in while (condition) { : argument is of length zero
What causes this error message, and what does it mean?
On further inspection it seems that the value is NULL.
condition
## NULL
In order to deal with this error, how do I test for NULL values?
I expected that this would return TRUE, but I got an empty logical value:
condition == NULL
## logical(0)
See ?NULL
You have to use is.null
‘is.null’ returns ‘TRUE’ if its argument is ‘NULL’ and ‘FALSE’
otherwise.
Try this:
if ( is.null(hic.data[[z]]) ) { print("is null")}
From section 2.1.6 of the R Language Definition
There is a special object called NULL. It is used whenever there is a need to indicate or
specify that an object is absent. It should not be confused with a vector or list of zero
length.
The NULL object has no type and no modifiable properties. There is only one NULL object
in R, to which all instances refer. To test for NULL use is.null. You cannot set attributes
on NULL.
What causes this error message, and what does it mean?
if statements take a single logical value (technically a logical vector of length one) as an input for the condition.
The error is thrown when the input condition is of length zero. You can reproduce it with, for example:
if (logical()) {}
## Error: argument is of length zero
if (NULL) {}
## Error: argument is of length zero
Common mistakes that lead to this error
It is easy to accidentally cause this error when using $ indexing. For example:
l <- list(a = TRUE, b = FALSE, c = NA)
if(l$d) {}
## Error in if (l$d) { : argument is of length zero
Also using if-else when you meant ifelse, or overriding T and F.
Note these related errors and warnings for other bad conditions:
Error in if/while (condition) {: missing Value where TRUE/FALSE needed
Error in if/while (condition) : argument is not interpretable as logical
if (NA) {}
## Error: missing value where TRUE/FALSE needed
if ("not logical") {}
## Error: argument is not interpretable as logical
if (c(TRUE, FALSE)) {}
## Warning message:
## the condition has length > 1 and only the first element will be used
How do I test for such values?
NULL values can be tested for using is.null. See GSee's answer for more detail.
To make your calls to if safe, a good code pattern is:
if(!is.null(condition) &&
length(condition) == 1 &&
!is.na(condition) &&
condition) {
# do something
}
You may also want to look at assert_is_if_condition from assertive.code.
When testing for NULL values, you want to use is.null(hic.data[[z]]).

Simple if-else loop in R

Can someone tell me what is wrong with this if-else loop in R? I frequently can't get if-else loops to work. I get an error:
if(match('SubjResponse',names(data))==NA) {
observed <- data$SubjResponse1
}
else {
observed <- data$SubjResponse
}
Note that data is a data frame.
The error is
Error in if (match("SubjResponse", names(data)) == NA) { :
missing value where TRUE/FALSE needed
This is not a full example as we do not have the data but I see these issues:
You cannot test for NA with ==, you need is.na()
Similarly, the output of match() and friends is usually tested for NULL or length()==0
I tend to write } else { on one line.
As #DirkEddelbuettel noted, you can't test NA that way. But you can make match not return NA:
By using nomatch=0 and reversing the if clause (since 0 is treated as FALSE), the code can be simplified. Furthermore, another useful coding idiom is to assign the result of the if clause, that way you won't mistype the variable name in one of the branches...
So I'd write it like this:
observed <- if(match('SubjResponse',names(data), nomatch=0)) {
data$SubjResponse # match found
} else {
data$SubjResponse1 # no match found
}
By the way if you "frequently" have problems with if-else, you should be aware of two things:
The object to test must not contain NA or NaN, or be a string (mode character) or some other type that can't be coerced into a logical value. Numeric is OK: 0 is FALSE anything else (but NA/NaN) is TRUE.
The length of the object should be exactly 1 (a scalar value). It can be longer, but then you get a warning. If it is shorter, you get an error.
Examples:
len3 <- 1:3
if(len3) 'foo' # WARNING: the condition has length > 1 and only the first element will be used
len0 <- numeric(0)
if(len0) 'foo' # ERROR: argument is of length zero
badVec1 <- NA
if(badVec1) 'foo' # ERROR: missing value where TRUE/FALSE needed
badVec2 <- 'Hello'
if(badVec2) 'foo' # ERROR: argument is not interpretable as logical

Resources