From tplate at acm.org  Thu Sep  3 00:50:18 2009
From: tplate at acm.org (Tony Plate)
Date: Wed, 02 Sep 2009 16:50:18 -0600
Subject: [Rd] Documentation for is.atomic and is.recursive
In-Reply-To: <4A9EE3D8.7040008@stats.uwo.ca>
References: <8b356f880909021139pa07d922q1f1c28a0fb70cdbe@mail.gmail.com>		<4A9EC967.3080507@stats.uwo.ca>	<8b356f880909021310l3805de62g2c2467db9a1591d2@mail.gmail.com>
	<4A9EE3D8.7040008@stats.uwo.ca>
Message-ID: <4A9EF6AA.1010204@acm.org>

Duncan Murdoch wrote:
> On 02/09/2009 4:10 PM, Stavros Macrakis wrote:
>> Let us stipulate that the current wording can be construed to be 
>> correct.
>
> I'd rather just state that the current wording is correct, without the 
> weasel words.
>
>> I would nonetheless claim that the documentation as currently written
>> is at best ambiguous and confusing, and would benefit from improved
>> wording.
>
> A claim that documentation would benefit from improved wording is a 
> tautology.  A claim that the documentation is ambiguous requires more 
> evidence than you've offered.  You have demonstrated that someone 
> could be confused when reading it, but that isn't necessarily our 
> responsibility.
>
> Duncan Murdoch
>
I suspect the confusion comes from the mistaken, but very 
understandable, interpretation that the phrase "'x' is a vector" in the 
documentation should somehow equate with the R function call 
'is.vector(x)'.  Similar potentially misleading wording appears in the 
"Description" for ?is.vector:
   "|is.vector| returns |TRUE| if |x| is a vector (of mode logical, 
integer, real, complex, character, raw or list if not specified) or 
expression and |FALSE|".
However, the Details for ?is.vector do clarify, saying:
  "|is.vector| returns |FALSE| if |x| has any attributes except names."

Here are some concrete suggestions for improving the documentation:
(1) In the Details or Note section for ?is.atomic, add the paragraph:
"is.atomic is unaffected by the presence of attributes on 'x', unlike 
is.vector (which would probably be better named is.bare.vector).  
is.atomic(x) merely tests whether the data mode of x is an atomic vector 
type, and ignores whether or not x has attributes.  The behavior of 
is.vector(x) is quite different -- it tests whether x is a bare vector.  
is.vector can be TRUE for lists and expressions as well as atomic vector 
types, but if there are attributes other than names on x, is.vector(x) 
returns FALSE."

(2) In the Description section for ?is.vector, change
  "|is.vector| returns |TRUE| if |x| is a vector (of mode logical, 
integer, real, complex, character, raw or list if not specified) or 
expression"
to
  "|is.vector| returns |TRUE| if |x| is a bare vector (of mode logical, 
integer, real, complex, character, raw or list if not specified, with no 
attributes other than names), or expression with no attributes other 
than names"

-- Tony Plate

>>
>> What would be lost by that?
>>
>>> One could argue that in R's pre-history we should have had is.atomic 
>>> imply
>>> is.vector, but that's not how things are documented, and I think we're
>>> pretty much stuck with the definitions we've got on low level 
>>> functions like
>>> those.
>>
>> I explicitly said in my mail that I was not suggesting that past
>> design decisions (wise or unwise) be revisited; only that they be
>> documented more clearly.
>>
>>                -s
>>
>> On Wed, Sep 2, 2009 at 3:37 PM, Duncan Murdoch<murdoch at stats.uwo.ca> 
>> wrote:
>>> On 9/2/2009 2:39 PM, Stavros Macrakis wrote:
>>>> The documentation for is.atomic and is.recursive is inconsistent with
>>>> their behavior in R 2.9.1 Windows.
>>>>
>>>> ? is.atomic
>>>>
>>>>     'is.atomic' returns 'TRUE' if 'x' is an atomic vector (or 'NULL')
>>>>     and 'FALSE' otherwise.
>>>>     ...
>>>>     'is.atomic' is true for the atomic vector types ('"logical"',
>>>>     '"integer"', '"numeric"', '"complex"', '"character"' and '"raw"')
>>>>     and 'NULL'.
>>>>
>>>> This description implies that is.atomic(x) implies is.vector(x)
>>>> (assuming that an "atomic vector type" is a subset of a "vector
>>>> type").  But in fact that is not true for values with class
>>>> attributes:
>>> I don't see is.vector mentioned there.  The description of is.vector 
>>> on its
>>> own man page implies the behaviour below; I think the description of
>>> is.atomic that you quote above is also consistent with the behaviour.
>>>
>>> One could argue that in R's pre-history we should have had is.atomic 
>>> imply
>>> is.vector, but that's not how things are documented, and I think we're
>>> pretty much stuck with the definitions we've got on low level 
>>> functions like
>>> those.
>>>
>>>
>>>> is.atomic(factor(3)) => TRUE
>>>> is.vector(factor(3)) => FALSE
>>>>
>>>> is.atomic(table(3)) => TRUE
>>>> is.vector(factor(3)) => FALSE
>>>>
>>>> It appears, then, that is.atomic requires only that unclass(x) be an
>>>> atomic vector, not that x be an atomic vector.
>>>>
>>>> There is also another case where is.atomic(x) != 
>>>> is.vector(unclass(x)):
>>>>
>>>> is.atomic(NULL) => TRUE
>>>> is.vector(NULL) => FALSE
>>>>
>>>> It would be useful to make the documentation consistent with the
>>>> implementation. (Presumably by updating the documentation, not
>>>> changing the behavior.)
>>>>
>>>> The documentation continues:
>>>>
>>>>     'is.recursive' returns 'TRUE' if 'x' has a recursive (list-like)
>>>>     structure and 'FALSE' otherwise.
>>>>     ...
>>>>     Most types of language objects are regarded as recursive: those
>>>>     which are not are the atomic vector types, 'NULL' and symbols (as
>>>>     given by 'as.name').
>>>>
>>>> But is.recursive(as.name('foo')) == is.recursive(quote(foo)) == FALSE.
>>> That's what it says should happen.  symbols such as as.name('foo') 
>>> are not
>>> recursive.
>>>
>>> Duncan Murdoch
>>>
>>>> Again, it would be useful to make the documentation consistent with
>>>> the implementation.
>>>>
>>>> To summarize all this in a table of the most common datatypes:
>>>>
>>>> outerl <-
>>>>  function(f, a, b)
>>>>    structure(outer(a,b,Vectorize(f)),
>>>>              dimnames=list(a,b))
>>>>
>>>> outerl(function(x,f)(match.fun(f))(x),
>>>>
>>>> list(3,factor(c("a","b")),NULL,function()3,as.name("foo"),environment()), 
>>>>
>>>>
>>>> list("class","mode","storage.mode","is.vector","is.atomic","is.recursive")) 
>>>>
>>>>
>>>>              class         mode          storage.mode  is.vector
>>>> is.atomic is.recursive
>>>> 3             "numeric"     "numeric"     "double"      "TRUE"
>>>> "TRUE"    "FALSE"           <<< OK
>>>> 1:2           "factor"      "numeric"     "integer"     "FALSE"
>>>> "TRUE"    "FALSE"             <<< inconsistent
>>>> NULL          "NULL"        "NULL"        "NULL"        "FALSE"
>>>> "TRUE"    "FALSE"         <<< inconsistent
>>>> function ()   "function"    "function"    "function"    "FALSE"
>>>> "FALSE"   "TRUE"          <<< OK
>>>> foo           "name"        "name"        "symbol"      "FALSE"
>>>> "FALSE"   "FALSE"          <<< inconsistent
>>>> <environment> "environment" "environment" "environment" "FALSE"
>>>> "FALSE"   "TRUE"     <<< OK
>>>>
>>>> Thanks,
>>>>
>>>>           -s
>>>>
>>>> ______________________________________________
>>>> R-devel at r-project.org mailing list
>>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>>
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>



[Rd] Documentation for is.atomic and is.recursive
Tony Plate