From ripley at stats.ox.ac.uk  Wed May 24 06:03:10 2006
From: ripley at stats.ox.ac.uk (Prof Brian Ripley)
Date: Wed, 24 May 2006 05:03:10 +0100 (BST)
Subject: [Rd] protect
In-Reply-To: <41698F04-2224-457D-8A9A-9613A7A03F84@stat.Berkeley.EDU>
References: <35168A7B-DFA1-42F7-8763-7769B449005B@stat.berkeley.edu>
	<Pine.LNX.4.64.0605230814250.17904@gannet.stats.ox.ac.uk>
	<Pine.LNX.4.64.0605230852590.23195@gannet.stats.ox.ac.uk>
	<41698F04-2224-457D-8A9A-9613A7A03F84@stat.Berkeley.EDU>
Message-ID: <Pine.LNX.4.64.0605240458050.6058@gannet.stats.ox.ac.uk>

On Tue, 23 May 2006, Kasper Daniel Hansen wrote:

> Thank you very much. I think I do have a clearer understanding, but I have a 
> few questions
>
> On May 23, 2006, at 12:55 AM, Prof Brian Ripley wrote:
>
>> On Tue, 23 May 2006, Prof Brian Ripley wrote:
>> 
>>> On Mon, 22 May 2006, Kasper Daniel Hansen wrote:
>>> 
>>>> I have a few simple questions about the usage of PROTECT, more
>>>> specifically how careful one needs to be. Simple yes/no answers are
>>>> fine.
>>> 
>>> (Except that in the last case they would be misleading.)
>>> 
>>>> Most of the uses I have seen do protection when memory is allocated.
>>>> But what if one just want to assign a value of another function to a
>>>> variable. Say eg. that foo is a function that returns a SEXP. Would
>>>> the following code be fine?
>>>> 
>>>> SEXP bar;
>>>> PROTECT(bar = foo());
>>> 
>>> It would be fine but may be unnecessary.  It is objects and not pointers
>>> which are protected, and a SEXP is a pointer.  So protection is needed
>>> only if foo() might return a pointer to an unprotected object.
>
> Ok. I have been coding foo in such a way that I unprotect everything in foo 
> just before returning its value. I thought that was the "standard" way to do 
> - is that true? Or should I leave the return value protected and then 
> unprotect in the function calling foo?

That is indeed standard.  The issue is rather that if say foo() extracts 
an element of a list which has an R-level name, you know that it is 
already protected.

>>>> Also, basically in one use case I would want to return the value of
>>>> foo immediately, but I need to do some cleaning up first, which has
>>>> nothing to do with R (more specifically, I need to close various
>>>> files). Would I then need to protect foo, as in
>>>> 
>>>> SEXP bar;
>>>> bar = foo();
>>>> "close the file in C++"
>>>> return bar;
>>> 
>>> Fine, as PROTECT protects against R garbage collection, and that can only
>>> happen if R's functions are called.
>>> 
>>>> Finally, I am also assigning values to the components of a list.
>>>> Would the following be ok
>>>> 
>>>> SEXP bar;
>>>> PROTECT(bar = NEW_LIST(2));
>>>> SET_VECTOR_ELT(bar, 0, ScalarInteger(test());
>>>> 
>>>> (where test is a function returning int, which again has nothing to
>>>> do with R - it interfaces to an extern library), or do I need to
>>>> hedge myself against garbage collection in the SET_VECTOR_ELT macro?
>>> 
>>> You do need to protect but elsewhere in this call, as ScalarInteger does
>>> memory allocation:
>>> 
>>> INLINE_FUN SEXP ScalarInteger(int x)
>>> {
>>>    SEXP ans = allocVector(INTSXP, 1);
>>>    INTEGER(ans)[0] = x;
>>>    return ans;
>>> }
>>> 
>>> but SET_VECTOR_ELT does not.  So you need
>>> 
>>> SEXP bar, tmp;
>>> PROTECT(bar = NEW_LIST(2));
>>> PROTECT(tmp = test());
>>> SET_VECTOR_ELT(bar, 0, ScalarInteger(tmp));
>>> UNPROTECT(1);
>> 
>> Or a design that uses fewer PROTECTs
>> 
>> SEXP bar, tmp;
>> PROTECT(bar = allocVector(VECSXP, 2));
>> tmp = allocVector(INTSXP, 1);
>> SET_VECTOR_ELT(bar, 0, tmp);
>> INTEGER(tmp)[0] = test();
>
> I thought I got this. Then I grepped the sources and found this in 
> main/platform.c:
>
>   PROTECT(ans = allocVector(VECSXP, 18));
>   PROTECT(nms = allocVector(STRSXP, 18));
>   SET_STRING_ELT(nms, 0, mkChar("double.eps"));
>   SET_VECTOR_ELT(ans, 0, ScalarReal(R_AccuracyInfo.eps));
>
> This looks very similar to what I did above. In my case "test" was a C++ 
> function coming from outside of R returning an int. That was perhaps not 
> clear from my original mail, since the first suggested correction had
> PROTECT(tmp = test());
> indicating that the return value for test is a SEXP. Or am I completely of?

If test() iself does not use anthing from R (that it is C++ is enough of 
the story), then you do not need to protect it.  Or as in the platform.c 
example, if it is a constant.  Sorry, the caveats were not clear to me, 
and I tend not to rely on them as people do sometimes change functions.

> I have tried running my original suggestion with gctorture(TRUE) and it did 
> not give any errors. But neither did the second suggested correction.


-- 
Brian D. Ripley,                  ripley at stats.ox.ac.uk
Professor of Applied Statistics,  http://www.stats.ox.ac.uk/~ripley/
University of Oxford,             Tel:  +44 1865 272861 (self)
1 South Parks Road,                     +44 1865 272866 (PA)
Oxford OX1 3TG, UK                Fax:  +44 1865 272595



[Rd] protect
Prof Brian Ripley