From murdoch at stats.uwo.ca  Mon Jan 21 16:24:42 2008
From: murdoch at stats.uwo.ca (Duncan Murdoch)
Date: Mon, 21 Jan 2008 10:24:42 -0500
Subject: [Rd] experiments with slot functions and possible problems NOTE
In-Reply-To: <4794B321.6030907@tu-dresden.de>
References: <47949E59.9070603@tu-dresden.de> <4794A234.5050008@stats.uwo.ca>
	<4794B321.6030907@tu-dresden.de>
Message-ID: <4794B93A.6050309@stats.uwo.ca>

On 1/21/2008 9:58 AM, Thomas Petzoldt wrote:
> Hello Duncan,
> 
> thank you very much for your prompt reply. When I interpret your answer
> correctly there seems to be no alternative than either:
> 
> A) using lots of (possibly private) functions in the package or,
> B) define dummies for all functions which are in such lists or,
> C) ignore the NOTE, knowing that it is spurious (BTW: there are several
> prominent packages on CRAN with unresolved NOTEs).
> 
> The problem with A is, that it is my intention to have different
> versions of particular functions which should be organized as consistent
> sets. On the other hand, version B) is similarly inelegant as it
> requires lots of "obsolete code". I already had this idea but found it
> awkward because it would look more like Pascal where one has separate
> interface and implementation.

There's another way, which is more R-like, if you really want to avoid 
lots of private functions.  That is to create your lists via a function, 
and define the functions in the lists locally within the creator.  That 
is, something like this:

MakeListA <- function() {
   foo <- function() {
       1:10
   }
   bar <-function() {
        log(foo())
   }
   return(list(foo = foo, bar = bar))
}

fListA <- MakeListA()

This avoids the explicit environment manipulations.  Because both foo 
and bar are defined locally within MakeListA, they share an environment 
there, and can see each other (and anything else you chose to define 
locally within MakeListA.)

A big more way down below...

> 
> Duncan Murdoch wrote:
>> On 1/21/2008 8:30 AM, Thomas Petzoldt wrote:
>>> Hello,
>>>
>>> first of all, thanks to LT for \pkg{codeutils}. I agree that it is
>>> indeed very useful to identify errors and also to encourage re-thinking
>>> past solutions. My problem:
>>>
>>> I want to compare different sets of related sub-functions which should
>>> be used alternatively by the same top-level function. Sets of related
>>> functions should be bound together (as lists) and the workspace should
>>> be as clean as possible.
>>>
>>> Finally, these functions are to be called by top-level functions that
>>> work with such sets.
>>>
>>> What's the best way to do this?
>>>
>>> - clutter the workspace with lots of functions?
>>> OR:
>>> - ignore "notes about possible problems"
>>> OR:
>>> - a third way?
>>>
>>> Thanks in advance
>>>
>>> Thomas P.
> 
>>> An example:
>>>
>>> flistA <- list(
>>>    foo = function() {
>>>     1:10
>>>    },
>>>    bar = function() {
>>>      log(foo())
>>>    }
>>> )
>>>
> 
> [... main part of the example deleted, see original posting (TP)]
> 
>>> m2()
>>> # Error in bar() : could not find function "foo"
>> 
>> That's because the environment of bar was the evaluation frame in effect 
>> at the time it was created, and foo wasn't in that.  bar looks in its 
>> environment for non-local bindings.
> 
> Yes, of course. It simply shows that one can use non-nested functions
> but not interdependend functions without using attach or environment
> manipulations.
> 
>> 
>> Gabor's function edits the environment.
> 
> Yes, that's the intention and it works for me, but several people call
> it strange ;-)
> 
>>> m3()
>>> # works, but even in that case we get problems
>>> # if we do this in a package:
>>>
>>> # * checking R code for possible problems ... NOTE
>>> # bar: no visible global function definition for 'foo'
>> 
>> This is a spurious error:  codetools can't follow the strange stuff 
>> you're doing.
> 
> It is understandingly, that codetools cannot detect this. What about a
> mechanism (e.g. a declaration in the NAMESPACE) where one can state that
> one knows about this.
> 
>> I'd say the best approach would be to use lots of little functions, and 
>> a namespace to hide them.  Then codetools will be happy.  For example,
>> 
>> Afoo <- function() {
>>      1:10
>> }
>> Abar <-function() {
>>       log(Afoo())
>> }
>> fListA <- list(foo = Afoo, bar = Abar)
> 
> Yes, that's version A) after my nomencature.
> 
>> 
>> This won't allow global references to foo or bar to escape the watchful 
>> eye of codetools; if you want those, you'd do something like
>> 
>> foo <- function() stop("foo not initialized")
>> bar <- function() stop("bar not initialized")
> 
> Yes, seems like an approach using dummy functions.
> 
>> and later have
>> 
>> foo <- makefun1(fListA)
>> bar <- makefun2(fListA)
> 
> ... but I don't understand yet why you do it this way. In my example foo
> and bar are the "sub-functions" but makefun would return the toplevel
> functions.

I must have misunderstand your intention here.  I thought makefun1 was 
supposed to extract the foo member from fListA; I don't understand your 
distinction between toplevel and sub-functions.
> 
>> Duncan Murdoch
> 
> Nevertheless, thanks a lot for your assistance. I'm still a little bit
> optimistic that there may be a general alternative and I should tolerate
> C) (notes of codetools) a little time, but (if there is no alterative)
> use a combination between solution A) (default functions) or B) (dummies).

There are lots of possibilities; I'm sure we haven't exhausted them yet.

Duncan Murdoch
> 
> 
> Thomas P.
>



[Rd] experiments with slot functions and possible problems NOTE
Duncan Murdoch