From ross at biostat.ucsf.edu  Thu Sep 28 00:01:37 2006
From: ross at biostat.ucsf.edu (Ross Boylan)
Date: Wed, 27 Sep 2006 15:01:37 -0700
Subject: [Rd] S4 accessors
In-Reply-To: <451ABE22.90401@r-project.org>
References: <1159230049.7161.132.camel@iron.psg.net>
	<m2mz8n2prs.fsf@ziti.local>
	<1159291414.7161.143.camel@iron.psg.net>
	<m21wpyzfph.fsf@ziti.local>
	<1159299299.7161.239.camel@iron.psg.net>
	<451A8B95.8050406@r-project.org> <m24putmigh.fsf@ziti.local>
	<451ABE22.90401@r-project.org>
Message-ID: <20060927220137.GA29358@wheat.betterworld.us>

I'm trying to understand what the underlying issues are here--with the
immediate goal of how that affects my design and documentation
decisions.

On Wed, Sep 27, 2006 at 02:08:34PM -0400, John Chambers wrote:
> Seth Falcon wrote:
> > John Chambers <jmc at r-project.org> writes:
> >
> >   
> >> There is a point that needs to be remembered in discussions of
> >> accessor functions (and more generally).
> >>
> >> We're working with a class/method mechanism in a _functional_
> >> language.  Simple analogies made from class-based languages such as
> >> Java are not always good guides.
> >>
> >> In the example below, "a function foo that only operates on that
> >> class" is not usually a meaningful concept in R.   

The sense of "meaningful" here is hard for me to pin down, even with
the subsequent discussion.

I think the import is more than formal: R is not strongly typed, so
you can hand any argument to any function and the language will not
complain.

> >>     
> >
> > If foo is a generic and the only method defined is for class Bar, then
> > the statement seems meaningful enough?
> >   
> 
> This is not primarily a question about implementation but about what the 
> user understands.   IMO, a function should have an intuitive meaning to 
> the user.  Its name is taking up a "global" place in the user's brain, 
> and good software design says not to overload users with too many 
> arbitrary names to remember.

It's true that clashing uses of the same name may lead to confusion,
but that need not imply that functions must be applicable to all
objects.  Many functions only make sense in particular contexts, and
sometimes those contexts are quite narrow.

One of the usual motivations for an OO approach is precisely to limit
the amount of global space taken up by, for example, functions that
operate on the class (global in both the syntactic sense and in the
inside your brain sense).  Understanding a traditional OO system, at
least for me, is fundamentally oriented to understanding the objects
first, with the operations on them as auxiliaries.  As you point out,
this is just different from the orientation of a functional language,
which starts with the functions.

> 
> To be a bit facetious, if "flag is a slot in class Bar, it's really not 
> a good idea to define the accessor for that slot as
>  flag <- function(object)object at flag
> 
> Nor is the situation much improved by having flag() be a generic, with 
> the only method being for class Bar.  We're absconding with a word that 
> users might think has a general meaning.  OK, if need be we will have 
> different flag() functions in different packages that have _different_ 
> intuitive interpretations, but it seems to me that we should try to 
> avoid that problem when we can.
> 
> OTOH, it's not such an imposition to have accessor functions with a 
> syntax that includes the name of the slot in a standardized way:
>   get_flag(object)
> (I don't have any special attachment to this convention, it's just there 
> for an example)

I don't see why get_flag differs from flag; if "flag" lends itself to
multiple interpretations or meanings, wouldn't "get_flag" have the
same problem?

Or are you referring to the fact that "flag" sounds as if it's a verb
or action?  That's a significant ambiguity, but there's nothing about
it that is specific to a functional approach.

>   
> >   
> >> Functions are first-class objects and in principle every function
> >> should have a "function", a purpose.  Methods implement that purpose
> >> for particular combinations of arguments.
> >>

If this is a claim that every function should make sense for every
object, it's asking too much.  If it's not, I don't really see how a
function can avoid having a purpose.  The purpose of accessor
functions is to get or set the state of the object.

> >> Accessor functions are therefore a bit anomalous.  
> >>     
> >
> > How?  A given accessor function has the purpose of returning the
> > expected data "contained" in an instance.  It provides an abstract
> > interface that decouples the structure of the class from the data it
> > needs to provide to users.
> >   
> 
> See above.  That's true _if_ the name or some other syntactic sugar 
> makes it clear the this is indeed an accessor function, but not otherwise.

Aside from the fact that I don't see why get_flag is so different from
flag, the syntactic sugar argument has another problem.  The usually
conceived purpose of accessors is to hide from the client the
internals of the object.  To take an example that's pretty close to
one of my classes, I want startTime, endTime, and duration.
Internally, the object only needs to hold 2 of these quantities to get
the 3rd, but I don't want the client code to be aware of which choice
I made.  In particular, I don't what the client code to change from 
duration to get_duration if I switch to a representation that stored
the duration as a slot.

Ross




[Rd] S4 accessors
Ross Boylan