I spy a strange thing
with my innocent eye. I was testing spread_to_list, the function I wrote about in “How Best to Convert a Names-Values Tibble to a Named List?”. One of my tests passed it a zero-row tibble, expecting that the result would be a zero-element list:
test_that( "Test on zero-element tibble", {
t <- tribble( ~a, ~b )
l <- spread_to_list( t )
expect_that( length( l ), equals( 0 ) )
expect_that( l, is_identical_to( list() ) )
})
But it wasn’t. Or at least, it was, but with an unsuspected outgrowth.
The package I used to run that test is Hadley Wickham’s testthat, explained in
his 2011 article
“testthat: Get Started with Testing”. Even if you don’t know it, you can predict from his well-chosen function names what two things I expected. The first thing, that the result be length zero, came true. The second thing, that it be an empty list, didn’t.
Output from the test gave me a hint:
Error: Test failed: 'Test on zero-element tibble' * `l` not identical to list(). Attributes: < Modes: list, NULL > Attributes: < Lengths: 1, 0 > Attributes: < names for target but not for current > Attributes: < current is not list-like >
Displaying l and a list() told me the rest:
> l named list() > list() list()
A named list is not identical to a list, even when the set of names is empty. I don’t know whether this is reasonable or not. An empty set is unidentical to no set. On the other hand, a brick with no paint on it is identical to a brick with no paint on it, a piece of paper with no writing on it is identical to a piece of paper with no writing on it, and if you ride through the desert on a horse with no name you can at least remember your own. The R manual’s section on object attribute lists implies that a list’s names are an attribute. Let’s see how that behaves:
> attributes(l) $names character(0) > attributes(list()) NULL
So a list can either have no names and no box to put them in, or the box but nothing inside.