From murdoch.duncan at gmail.com  Mon Nov 17 17:19:34 2014
From: murdoch.duncan at gmail.com (Duncan Murdoch)
Date: Mon, 17 Nov 2014 11:19:34 -0500
Subject: [Rd] common base functions stripping S3 class
In-Reply-To: <CABdHhvEo0OfXC0-rfSJmiyh9XJ57MqCnWDpa3Buwfr0OOzdh4w@mail.gmail.com>
References: <CA+YV+Hx1qA_+JZ1QLo0D7Ckcc3A2sxa-ScAs5g44icfiO4DpnQ@mail.gmail.com>
	<54694BDA.10102@gmail.com>
	<CABdHhvEo0OfXC0-rfSJmiyh9XJ57MqCnWDpa3Buwfr0OOzdh4w@mail.gmail.com>
Message-ID: <546A2016.1020109@gmail.com>

On 17/11/2014 10:41 AM, Hadley Wickham wrote:
> > Generally the idea is that the class should be stripped because R has no
> > way of knowing if the new object, for example unique(obj), still has the
> > necessary properties to be considered to be of the same class as obj.
> > Only the author of the class knows that.  S4 would help a bit here, but
> > only structurally (it could detect when the object couldn't possibly be
> > of the right class), not semantically.
>
> There are two possible ways that S3 methods could handle subclasses:
>
> * preserve by default (would also have preserve all attributes)
> * drop by default
>
> If you could really on either system consistently, I think you could
> write correct code. It's very hard when the defaults vary.
>
> (In other words, I agree with everything you said, except I think if
> the default was to preserve you could still write correct code)

I don't see how default preserving could work.

For example, I might define a "SortedNumbers" class, which is a vector 
of numbers in non-decreasing order.  I could define min() and max() 
methods for it which would be really fast, because they only need to 
look at the first or last elements.  But a rev() method wouldn't make 
sense, so I wouldn't define one of those.

If the rev() default method left the class as "SortedNumbers", then my 
min() and max() calculations would end up broken.
So maybe I should have defined a rev() method that just stops with an 
error.  But classes don't own methods, so I'd have no way of knowing 
that someone else defined a new generic (e.g. shuffle()) that broke 
things.  I don't see any way around this within the S3 system.

In fact, some default methods do preserve the class, for example the 
replacement method `[<-`.  I could take a SortedNumbers vector of the 
numbers 1:10, and set element 1 to 11, and end up breaking min() and 
max().  This is a problem with the current design.

Probably we should do a better job of documenting which methods preserve 
the class and which ones don't.  (For example, `[` doesn't preserve the 
class, even though it would be fine to do so in this example.)  But 
there are a lot of things to do, and this is one thing that is pretty 
easy to figure out without documentation, so I'd say it's a low priority.

Duncan Murdoch



[Rd] common base functions stripping S3 class
Duncan Murdoch