Re: Subclassing DateTime?

2017-04-30 Thread Thomas (HFM) Wyant

> On April 29, 2017 at 8:08 PM Zefram <zef...@fysh.org> wrote:
> 
> 
> Thomas (HFM) Wyant wrote:
> >It seems to me that in at least some such cases subclassing
> >DateTime would be a better alternative.
> 
> You've run into the terrible factoring of the DateTime system.  All three
> of the modules you named already suffer from it, but subclassing DateTime
> would make things worse.  For subclassing to be the right answer,
> the objects of your classes would have to be everything that DateTime
> objects are, plus something that you're adding.  But one of the things
> that DateTime objects are is Gregorian, which your objects are not.
> 
> -zefram

Well, before I adopted the nasssty Hobbitsesss calendar I wrote my own 
never-published Shire Calendar module that _was_ in fact a subclass of 
DateTime. It overrode a pot load of public methods, of course, plus private 
methods _maybe_future_dst_warning(), _month_length(), _new(), _rd2ymd(), and 
_ymd2rd(). And, subject to the caveat that I never explored the corner cases 
(such as infinite times), it worked. But I was nervous about all the overridden 
private methods, plus the fact that I was relying on the DateTime internals 
(other than the ones I overrode) not to croak on a non-numeric day, plus 
probably other ad-hoc assumptions I do not now recall.

I suppose what I was hoping was that someone would come out of the woodwork and 
say something like "Oh, yes, there is a subclassing guide in such-and-such 
obscure place, and this list of private methods (including the ones I listed) 
should really be considered protected ..."

What I was trying to do before I wrote the note was to write a module (working 
name DateTime::Calendar::Framework) that was not a subclass of DateTime, but 
that passed the DateTime test suite. Then someone doing a non-Gregorian module 
could start from that and override what they needed to override (a lot in the 
case of the Shire calendar, or DateTime::Calendar::Discordian), but only public 
methods, and define any attributes they felt like. At the moment it passes all 
the tests through t/41cldr-format.t (except for t/09greg.t, which tests _rmd2yd 
and _yd2rmd, and which I skip, and except for a couple that access DateTime 
internals, which I modified). But t/42duration-class.t actually tests the 
subclassing of DateTime. I guess if I can't get it sorted out I can always mark 
the test TODO, document the associated restriction, and truck on.

Tom


Re: Subclassing DateTime?

2017-04-29 Thread Zefram
Thomas (HFM) Wyant wrote:
>It seems to me that in at least some such cases subclassing
>DateTime would be a better alternative.

You've run into the terrible factoring of the DateTime system.  All three
of the modules you named already suffer from it, but subclassing DateTime
would make things worse.  For subclassing to be the right answer,
the objects of your classes would have to be everything that DateTime
objects are, plus something that you're adding.  But one of the things
that DateTime objects are is Gregorian, which your objects are not.

-zefram


Subclassing DateTime?

2017-04-29 Thread Thomas (HFM) Wyant
Dear list,


A pattern seen frequently in DateTime::Calendar-like modules is to put the 
functionality in a top-level module which holds a DateTime object to do the 
DateTime-specific stuff. If you want anything like the full DateTime 
functionality this involves writing a bunch of methods on the order of


sub some_method { $_[0]->{dt}->some_method( @_[ 1 .. $#_ ] ) }


Fortunately if I turn off strict refs the methods can be defined in a loop by 
assigning an anonymous subroutine to a glob. But the above is not the only 
subroutine template, merely the most common.


It seems to me that in at least some such cases subclassing DateTime would be a 
better alternative. But I find no documentation on how to do this. I made a 
sort of middle-level pass through http://datetime.perl.org/, and browsed the 
mailing list archives back to 2012 or so. Did I miss the documentation somehow? 
If so, could someone give me a pointer to it?


The main issue I see are:

* Where can I, in some supported way, stash any extra attribute values?

* Is there a naming convention to avoid method name conflicts (i.e. 
unintentional overrides), especially for private methods?


You can stop reading here unless you are curious about what motivated the 
question. Feel free to snip it in a reply.


My reason for asking is that I have adopted a couple modules that use this 
pattern: DateTime::Calendar::Christian and 
DateTime::Fiction::JRRTolkien::Shire. Both were missing some DateTime 
functionality of interest to me -- a lot in the latter case. A bunch of methods 
had to be written to get it, and these methods have a strong family resemblance.


When I was going through the process of adopting DateTime::Calendar::Christian 
I was offered DateTime::Calendar::Liturgical::Christian. I refused, because I 
do not have the religious background to understand the first thing about what 
feast we celebrate today or what color altar cloth to use; 
DateTIme::Calendar::Christian just does the Julian calendar before the 
conversion date and the Gregorian calendar after.


Well, I decided to take another look at 
DateTime::Calendar::Liturgical::Christian, found myself writing those same 
methods for a second or third time, and decided maybe some laziness was in 
order. I started writing a class that does not inherit from DateTime but uses 
the $self->{dt} pattern, AND that passes all the DateTime tests. This is mostly 
just drudgery, but the methods that take two DateTime arguments (e.g. 
subtract_datetime()) are turning out to be problematic. So I thought, 
belatedly, that I would look into doing the simple obvious thing rather than 
the complex obscure thing.


Thanks,

Tom Wyant