Re: Parser/Backend API proposals

2003-01-17 Thread Dave Rolsky
On Fri, 17 Jan 2003, John Peacock wrote:

>  >  my $formatter =
>  >  DateTime::Formats::ISO8601->new
>  >  ( class => 'DateTime::Implementation::TAI64' );
>  >
>  >  my $dt = $formatter->parse( ... );
>
> That's OK, but too verbose for the average user, IMHO.  It also leaps too deeply
> into the API for my taste.  I would suggest that the average user shouldn't need
> to do anything more than
>
>   my $dt = DateTime->new($datestring);

The default constructor is going take components (year, month, day ...),
not a parseable string.

> and have that do something useful for the majority of the trivial cases.  I hate
> to keep bringing up Math::BigInt, but the model is very close to what I think is
> ideal.  The base package works out of the box, but if you want better
> performance, you add one line and your existing code works just the same, only
> faster:
>
>   use Math::BigInt; # implicitly uses Math::BigInt::Calc
>   use Math::BigInt lib => 'BitVect'; # faster backend
>
> and there is no need to change your existing code; I think it unlikely that
> anyone would want to use more than one storage/backend module at the same time.

So you're suggesting that DateTime.pm would be a factory class that might
instantiate some other implementation, based on a previously set class
variable?  That's fine.

> I also think I didn't explain my proposal sufficiently.  I would argue that the
> parser modules should be extremely thin and not full fledged constructors.  All
> that the parser would do is parse into a common format and leave the object
> creation to the storage module.

That's what DateTime::Formats::ICal does.  But the common format is a
named set of components.

> which is exactly my $obj->as_array method would return.  The reason that I

Right, I just like named parameters.

> suggested multiple possible parses is that some backends (like TAI) already have
> a conversion from a specific external representation to their internal
> representation.  If the array of arguments is agreed to be the most likely

I think for TAI this will have to deal with in the DateTime::Thingy::TAI64
module, not in a parser.  There's no reason to burden parser implementors
with having to create different sets of returns values just to handle
various implementations.

> "normalized" representation, I would actually have the Formats modules include
> only a single function Parse() which would return the normalized relationship
> (or undef if this parser cannot handle that date string).

That's more or less how DateTime::Formats::ICal works, except it returns a
DateTime.pm object.

>  > I think we should assume that creating a format/parse object will be
>  > one step, and actual parsing/formatting will be a different one.
>
> Why?  It requires the average user to know far more about the internals than is
> strictly necessary.  Sure, it has to be available for those who need it, but it
> shouldn't be the default interface.

Cause it's the simplest, least bizarre interface.  Everybody seems to have
different ideas about how to make this more convenient, but absent any
consensus I'll start with implementing the simple, least clever interface.

>  > I don't think the parser should be directly responsible for producing
>  > anything other than "DateTime.pm API-compliant object", which may or may
>  > not actually _be_ a DateTime.pm object.
>
> Well then we may be saying the same thing;  I want the parser to generate a
> normalized date format.  I'm just saying that making the parser itself an object
> is not _required_ to do that.

It's not required, but making it an object may be needed for other things.
For example, Date::Manip parsing is language dependent, so you may need
one object for English and one for French.

> Not at all.  DateTime is the gatekeeper class; it contains any overloading code
> (which you haven't really mentioned yet, have you?) as well as all of the

Overloading code is in there.

> No question.  Any implemention class will inherit all of the derivable methods
> and only implement/override the minority of primitive methods (like $obj->year
> for example).

Can you explain what the class hierarchy for DateTime.pm-API objects would
be?

Right now I'm thinking:

  DateTime.pm - implements reference API, with completely functional
internals

  DateTime::Implementation::TAI64 - implements same API.  Inherits from
DateTime.pm and overrides some methods.

Clearly you're thinking of something else but I don't understand what.


-dave

/*===
House Absolute Consulting
www.houseabsolute.com
===*/



Re: Parser/Backend API proposals

2003-01-17 Thread John Peacock
Dave Rolsky wrote:
> I should also point out I'm moving the ical-specific bits to
> DateTime::Formats::ICal.

As soon as SF gets their servers back in operation (what's up with that?), I'll
take a look at what you have.  My quicky module is not meant to be an example of
anything practical, just something to toy with.  In particular, you (in
particular) will blanche at the fact I used Autoloader (since that is what
h2xs normally includes), which is not friendly towards mod_perl code.

>  How about this instead:
>
>  my $formatter =
>  DateTime::Formats::ISO8601->new
>  ( class => 'DateTime::Implementation::TAI64' );
>
>  my $dt = $formatter->parse( ... );

That's OK, but too verbose for the average user, IMHO.  It also leaps too deeply
into the API for my taste.  I would suggest that the average user shouldn't need
to do anything more than

	my $dt = DateTime->new($datestring);

and have that do something useful for the majority of the trivial cases.  I hate
to keep bringing up Math::BigInt, but the model is very close to what I think is
ideal.  The base package works out of the box, but if you want better
performance, you add one line and your existing code works just the same, only
faster:

	use Math::BigInt; # implicitly uses Math::BigInt::Calc
	use Math::BigInt lib => 'BitVect'; # faster backend

and there is no need to change your existing code; I think it unlikely that 
anyone would want to use more than one storage/backend module at the same time.

I also think I didn't explain my proposal sufficiently.  I would argue that the 
parser modules should be extremely thin and not full fledged constructors.  All 
that the parser would do is parse into a common format and leave the object 
creation to the storage module.

>
> The assumption here is that there is a standard set of arguments which can
> be given to the constructor, which follows from the assumption that all
> DateTime "core object" implementations share an API.  These constructor
> arguments would probably be:
>
>   year, month, day
>   hour, minute, second
>   time_zone

which is exactly my $obj->as_array method would return.  The reason that I
suggested multiple possible parses is that some backends (like TAI) already have
a conversion from a specific external representation to their internal
representation.  If the array of arguments is agreed to be the most likely
"normalized" representation, I would actually have the Formats modules include
only a single function Parse() which would return the normalized relationship 
(or undef if this parser cannot handle that date string).

>
> I think we should assume that creating a format/parse object will be
> one step, and actual parsing/formatting will be a different one.

Why?  It requires the average user to know far more about the internals than is 
strictly necessary.  Sure, it has to be available for those who need it, but it 
shouldn't be the default interface.

>
> I don't think the parser should be directly responsible for producing
> anything other than "DateTime.pm API-compliant object", which may or may
> not actually _be_ a DateTime.pm object.

Well then we may be saying the same thing;  I want the parser to generate a 
normalized date format.  I'm just saying that making the parser itself an object 
is not _required_ to do that.

>
> So what's implemented in DateTime.pm in this idea?  Nothing?  If nothing,
> it might as well just return an object in a different class.  I don't
> think I understand what you're suggesting.

Not at all.  DateTime is the gatekeeper class; it contains any overloading code 
(which you haven't really mentioned yet, have you?) as well as all of the 
exposed API.  But it doesn't need to contain the actual code to implement the 
API, and I would argue, shouldn't.  See below

>
>
>>I have DateTime::Formats::ISO8601 done (well formed ISO dates only); I attach it
>>for your pleasure.  I can work on DateTime::Formats::Date_Parse for the more
>
>
> By "Date_Parse" do you mean complex Date::Manip style parsing?

No, actually I meant Graham Barr's Date::Parse (part of Time::Date).  Someone 
will likely want the Date::Manip parsing available as well.

>
> As to DateTime::Thingy::TAI64, I think it needs to do the following:
>
> - implement the same API as DateTime.pm, possibly adding some TAI64
> methods if that's useful
>
> - inherit from DateTime.pm - this follows from the former.  There's no
> reason to implement a method like "year_0", which is defined in
> DateTime.pm as:
>
>  sub year_0 { $_[0]->year - 1 }
>
> There's a number of other methods in DateTime.pm it'd be pointless to
> override as well, along these same lines.
>

No question.  Any implemention class will inherit all of the derivable methods 
and only implement/override the minority of primitive methods (like $obj->year 
for example).

John

--
John Peacock
Director of Information Research and Technology
Rowman & Littlefield Publishing Group
4720 Boston Way
Lanham, MD 20706
301-459-3366 x.5

Re: Parser/Backend API proposals

2003-01-17 Thread Dave Rolsky
On Thu, 16 Jan 2003, John Peacock wrote:

> I've been thinking about the API for parsers and storage methods and I have a
> different suggestion than what has been discussed before.  The current model
> seems to assume that there is a single DateTime object type, regardless of
> backend storage method.  Or at the very least, the current model will require
> additional backend work to completely emulate the existing scheme.  Although
> Date::ICal seems to be a fine base, others have already mentioned wanting to
> implement in other internal schemes, for example TAI64.

Yes, I expect there to be other DateTime.pm API implementations using
different internals, TAI64 being one obvious example.  A pure XS
implementation may also be useful, just for speed.

I should also point out I'm moving the ical-specific bits to
DateTime::Formats::ICal.  This'll be a good example parser/formatter, and
there's already working code for it, and tests that can be tweaked a bit.
It will also handle parsing & formatting DateTime::Duration objects, which
other DateTime::Formats::* modules may need to do as well.

> I suggest that the parsing modules (currently referred to as DateTime::Formats)
> be strictly limited to parsing some subset of the possible input formats and
> return an object with a few standard methods which would retrieve a normalized
> representation.  Then, the parsed and normalized object could be used by the
> chosen backend to store the date for later processing.
>
> For example, DateTime::Formats:: would return an object which would have the
> following methods:
>
>   $obj->as_array # "big endian" array of date/time values
>   $obj->as_unix_time # seconds since the epoch
>   $obj->as_string# some sort of "standard" text format
>   $obj->as_ical  # the ICal normalized format

 How about this instead:

 my $formatter =
 DateTime::Formats::ISO8601->new
 ( class => 'DateTime::Implementation::TAI64' );

 my $dt = $formatter->parse( ... );

The assumption here is that there is a standard set of arguments which can
be given to the constructor, which follows from the assumption that all
DateTime "core object" implementations share an API.  These constructor
arguments would probably be:

  year, month, day
  hour, minute, second
  time_zone

or something extremely similar.

This assumes that DateTime implementations would implement the same API as
DateTime.pm (maybe with extra methods), but that seems like a _good_
implementation.  I think it'd be confusing as hell if DateTime.pm offered
one set of get methods and DateTime::Implementation::TAI64 offered another
set.

> I've actually been programming some sample code, so for this object:
>
>   my $prs = DateTime::Formats::ISO8601("1998-06-03T12:30:01");
>
> you would have these possible methods:
>
>  $prs->as_array => ARRAY(0x8064c68)
> 0  1998
> 1  06
> 2  03
> 3  12
> 4  30
> 5  01
>  $prs->as_unix_time => 899483401
>  $prs->as_string => '1998-06-03T12:30:01'
>  $prs->as_ical => '19980603T123001'

I think we should assume that creating a format/parse object will be
one step, and actual parsing/formatting will be a different one.

I don't think the parser should be directly responsible for producing
anything other than "DateTime.pm API-compliant object", which may or may
not actually _be_ a DateTime.pm object.

> I would suggest that the DateTime objects themselves simply be a wrapper for the
> DateTime::Storage:: module, which itself would rely on the DateTime::Format
> modules to provide it with a normalized date format.  The DateTime->new() method
> would be very shallow:
>
> ...
>  my $self = {
>  DATE => DateTime::Storage->new(DateTime::Format->new($val)),
>  };
>
>  bless $self, $class;

So what's implemented in DateTime.pm in this idea?  Nothing?  If nothing,
it might as well just return an object in a different class.  I don't
think I understand what you're suggesting.

> I have DateTime::Formats::ISO8601 done (well formed ISO dates only); I attach it
> for your pleasure.  I can work on DateTime::Formats::Date_Parse for the more

By "Date_Parse" do you mean complex Date::Manip style parsing?

As to DateTime::Thingy::TAI64, I think it needs to do the following:

- implement the same API as DateTime.pm, possibly adding some TAI64
methods if that's useful

- inherit from DateTime.pm - this follows from the former.  There's no
reason to implement a method like "year_0", which is defined in
DateTime.pm as:

 sub year_0 { $_[0]->year - 1 }

There's a number of other methods in DateTime.pm it'd be pointless to
override as well, along these same lines.


-dave

/*===
House Absolute Consulting
www.houseabsolute.com
===*/