Re: Parser Interface (Was Re: Picking up the ball)

2003-01-16 Thread Dave Rolsky
On Thu, 16 Jan 2003, David Wheeler wrote:

> > Your first option is not on the table.  The options on the table are:
> >
> >   use DateTime;
> >   use DateTime::Parse::MySQL;
> >   my $dt = DateTime->from_mysql_datetime( $mysql_dt );
> >   print $dt->to_mysql_string();
> >
> > or
> >
> >   use DateTime;
> >   use DateTime::Parse::MySQL;
> >   my $dt = DateTime::Parse::MySQL->new_datetime( $mysql_dt );
> >   print DateTime::Parse::MySQL->mysql_datetime( $dt );
> >
> > Frankly, I think the first one is a lot easier to use and makes more
> > sense.  It's the decorator pattern without the dispatching overhead!
>
> Trying to catch up here a bit. It seems to me that the first option
> could just be a pass-through to the second.

I think #1 is off the table.  A few people liked it (including me), but
several were quite vehemently opposed to it.

I'll probably just go with the very straightforward API of:

 make a parsing object
 tell it to parse string X and return a DateTime

 make a formatting object
 tell it to format a DateTime object in a specific format

This isn't particularly clever, nor is it super-convenient.  But all the
clever and convenient suggestions seem to arouse more dislike from some
people, so it's easier to agree on the tried and true.  It might not be
ideal for anyone, but at least people who look at the modules will not be
turned off by an API they consider to abnormal ;)


-dave

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



Re: Parser Interface (Was Re: Picking up the ball)

2003-01-16 Thread David Wheeler
On Monday, January 13, 2003, at 07:14  PM, Dave Rolsky wrote:


Your first option is not on the table.  The options on the table are:

  use DateTime;
  use DateTime::Parse::MySQL;
  my $dt = DateTime->from_mysql_datetime( $mysql_dt );
  print $dt->to_mysql_string();

or

  use DateTime;
  use DateTime::Parse::MySQL;
  my $dt = DateTime::Parse::MySQL->new_datetime( $mysql_dt );
  print DateTime::Parse::MySQL->mysql_datetime( $dt );

Frankly, I think the first one is a lot easier to use and makes more
sense.  It's the decorator pattern without the dispatching overhead!


Trying to catch up here a bit. It seems to me that the first option 
could just be a pass-through to the second.

Regards,

David

--
David Wheeler AIM: dwTheory
[EMAIL PROTECTED] ICQ: 15726394
http://david.wheeler.net/  Yahoo!: dew7e
   Jabber: [EMAIL PROTECTED]



Re: Parser Interface (Was Re: Picking up the ball)

2003-01-14 Thread Matthew Simon Cavalletto
On Tuesday, January 14, 2003, at 12:55  PM, Dave Rolsky wrote:


   use DateTime;
   my $dt = DateTime->new( 'MySQL' => $mysql_dt );
   print $dt->to_string( 'MySQL' );

   use DateTime;
   use DateTime::Parse::MySQL;
   my $dt = DateTime->from_mysql_datetime( $mysql_dt );
   print $dt->to_mysql_string();


Um, yeah, the second is _much_ clearer.


[...] And if someone wants to build a separate implementation of the 
DateTime interface, like the TAI64 code, how will they be able to 
integrate with those parsing/formatting modules, short of blindly 
making their code a subclass of the primary implementation?

Yes, other implementations will blindly inherit from the base class. 
That's ok.  For example, it'll want to inherit things like strftime 
and so on.

My suggestion would be that strftime also be placed in an external 
module.

  package DateTime::Format::strtime;

  sub string_to_rdsec { ... } # strptime

  sub rdsec_to_string { ... } # strftime

This same interface could be used polymorphically for any date 
parsing/stringification library, and can be used directly by other 
modules, in addition to via a DateTime object.

Users could be isolated from this behind the current interface:

  package DateTime;
  require DateTime::Format::strtime;

  sub strptime {
(shift)->new( DateTime::Format::strtime->string_to_rdsec( @_ ) )
  }

  sub strftime {
DateTime::Format::strtime->rdsec_to_string( (shift)->as_rdsec, @_ )
  }

Modules like Date::Discordian or Date::Maya, which have no internal 
storage format and only exist to convert to and from other calendar 
formats, could easily be refactored to follow this interface.

  my $dt = DateTime->new(  );

  print $dt->to_string( strftime => $fmt );
  # Calls DateTime::Format::strtime::rdsec_to_string($rd, $sec, $fmt)

  print $dt->to_string( 'Discordian' );
  # Calls DateTime::Format::Discordian::rdsec_to_string($rd, $sec)

Your first option is not on the table.


Er, why not?


Cause I don't like it.


Ouch.


Some decisions have to be made by fiat, because as we can see there 
are lots of people with different, conflicting, valid opinions.  But 
in the end, we need one consistent API.  Since I'm in charge (FWIW) 
that means I'm the one who gets to decide what goes in and what 
doesn't.

I agree that a certain amount of that approach is needed, but taken to 
extremes this may doom the project to being just another contender in 
the date/time space, rather than the open framework everyone 
standardizes on and interoperates with.

The options on the table are: [...]


That's a straw man -- AFAIK, nobody's suggesting this kind of API.


I was, actually.


OK, sorry for the confusion.


Decorators are a dynamic composition of objects, nestable such that 
you can stick one decorator in front of another, and each one is 
provided by a different class and so has its own namespace and 
inheritance tree.

Thanks, I know what a decorator is in GoF-speak ;)

This achieves exactly the same thing as a decorator, without a whole 
stack of objects needed.

Regardless, the point I've been trying to make is that we don't want 
Decorators.

We want something more like Strategies (ie, given several similar 
algorithms, rather than having a bunch of different methods or a big 
case statement, put each in its own class and call them as needed):

  http://c2.com/cgi/wiki?StrategyPattern

On Tuesday, January 14, 2003, at 01:07  PM, Dave Rolsky wrote:
I'm very strongly opposed to something that just passes random strings 
into new() and then loads the module on demand.

They're not random strings, they're class names; passing classes as 
arguments is common OO framework practice.

We could turn off on-demand module loading, or default to off unless 
you explicitly request it, if that part seems undesirable.

-Simon



Re: Parser Interface (Was Re: Picking up the ball)

2003-01-14 Thread John Peacock
Dave Rolsky wrote:

  use DateTime;
  use DateTime::Parse::MySQL;
  my $dt = DateTime::Parse::MySQL->new_datetime( $mysql_dt );
  print DateTime::Parse::MySQL->mysql_datetime( $dt );

I can also imagine some other scheme, where parse/format modules register
the formats they can handle with DateTime.pm.

But I'm very strongly opposed to something that just passes random strings
into new() and then loads the module on demand.



I guess that is the part that I don't understand.  If you have the ability to 
add new parsing methodology to a list, you can just as easily subtract.  So, if 
you want to use only the basic parsing and throw an error if you get a 
non-standard date format:

use DateTime ( parse => basic); # class-wide default
my $date1 = DateTime->new($dtstring); # better be ISO CCYYMMDD
my $sqldate = DateTime->new($sqlstr, parse => MySQL); # object override

etc.

This is a much more friendly interface for the average programmer.

John

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



Re: Parser Interface (Was Re: Picking up the ball)

2003-01-14 Thread Dave Rolsky
On Tue, 14 Jan 2003, Martijn van Beers wrote:

> > > Looking at the two alternatives, does the second really seem clearer?
> > >
> > >use DateTime;
> > >my $dt = DateTime->new( 'MySQL' => $mysql_dt );
> > >print $dt->to_string( 'MySQL' );
> > >
> > >use DateTime;
> > >use DateTime::Parse::MySQL;
> > >my $dt = DateTime->from_mysql_datetime( $mysql_dt );
> > >print $dt->to_mysql_string();
> >
> > Um, yeah, the second is _much_ clearer.  And its less error prone as well!
>
> Um, no it isn't.

Yes it is.  Your turn.

> > Your first option is not on the table.
>
> Let's put it on the table then. Much better than the other options.

No.  I already mentioned another option besides the second one up above.

  use DateTime;
  use DateTime::Parse::MySQL;
  my $dt = DateTime::Parse::MySQL->new_datetime( $mysql_dt );
  print DateTime::Parse::MySQL->mysql_datetime( $dt );

I can also imagine some other scheme, where parse/format modules register
the formats they can handle with DateTime.pm.

But I'm very strongly opposed to something that just passes random strings
into new() and then loads the module on demand.


-dave

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



Re: Parser Interface (Was Re: Picking up the ball)

2003-01-14 Thread Dave Rolsky
On Tue, 14 Jan 2003, Matthew Simon Cavalletto wrote:

> >> Looking at the two alternatives, does the second really seem clearer?
> >>
> >>use DateTime;
> >>my $dt = DateTime->new( 'MySQL' => $mysql_dt );
> >>print $dt->to_string( 'MySQL' );
> >>
> >>use DateTime;
> >>use DateTime::Parse::MySQL;
> >>my $dt = DateTime->from_mysql_datetime( $mysql_dt );
> >>print $dt->to_mysql_string();
> >
> > Um, yeah, the second is _much_ clearer.
>
> Hmm... Really? To me, the first seems much clearer.
>
> If this framework grows in the future, won't we end up with dozens of
> parser/formatter modules all stuffing methods into the base class?

Only if you load all of them.  Why would you do that?

> And if someone wants to build a separate implementation of the DateTime
> interface, like the TAI64 code, how will they be able to integrate with
> those parsing/formatting modules, short of blindly making their code a
> subclass of the primary implementation?

Yes, other implementations will blindly inherit from the base class.
That's ok.  For example, it'll want to inherit things like strftime and so
on.

> If there's a public consensus that most people prefer stuffing methods
> into the base package rather than having a gateway interface that
> dynamically dispatches calls to other classes, I'll drop the issue, but
> it seems to me like a significant mistake.

I haven't decided this is the way to go, but I don't like the "more params
to new()" way at all.

> > What if a specific parser needs _two_ params?
>
> Presumably it could accept an array-ref, or grab a list of arguments.

No, my point was what if I do this:

  my $dt = DateTime->new
   ( extended_parse => "Vendredi, la semaine prochaine",
 # Thursday, next week in French (I hope ;)
 language => 'French' );

The module that implements extended parsing will need to get at the
language parameter.  How will DateTime.pm know to pass that along?  I
guess it could just pass everything it got, though.

> > Your first option is not on the table.
>
> Er, why not?

Cause I don't like it.  Some decisions have to be made by fiat, because as
we can see there are lots of people with different, conflicting, valid
opinions.  But in the end, we need one consistent API.  Since I'm in
charge (FWIW) that means I'm the one who gets to decide what goes in and
what doesn't.

> > The options on the table are: [...] or
> >   use DateTime;
> >   use DateTime::Parse::MySQL;
> >   my $dt = DateTime::Parse::MySQL->new_datetime( $mysql_dt );
> >   print DateTime::Parse::MySQL->mysql_datetime( $dt );
>
> That's a straw man -- AFAIK, nobody's suggesting this kind of API.

I was, actually.

> Decorators are a dynamic composition of objects, nestable such that you
> can stick one decorator in front of another, and each one is provided
> by a different class and so has its own namespace and inheritance tree.
>http://web.media.mit.edu/~tpminka/patterns/Decorator.html

Thanks, I know what a decorator is in GoF-speak ;)

This achieves exactly the same thing as a decorator, without a whole stack
of objects needed.


-dave

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



Re: Parser Interface (Was Re: Picking up the ball)

2003-01-14 Thread Martijn van Beers
On Mon, Jan 13, 2003 at 09:14:25PM -0600, Dave Rolsky wrote:
> On Mon, 13 Jan 2003, Matthew Simon Cavalletto wrote:
> > Looking at the two alternatives, does the second really seem clearer?
> >
> >use DateTime;
> >my $dt = DateTime->new( 'MySQL' => $mysql_dt );
> >print $dt->to_string( 'MySQL' );
> >
> >use DateTime;
> >use DateTime::Parse::MySQL;
> >my $dt = DateTime->from_mysql_datetime( $mysql_dt );
> >print $dt->to_mysql_string();
> 
> Um, yeah, the second is _much_ clearer.  And its less error prone as well!
Um, no it isn't.

> Your first option is not on the table.
Let's put it on the table then. Much better than the other options.


Martijn



Re: Parser Interface (Was Re: Picking up the ball)

2003-01-14 Thread Matthew Simon Cavalletto
On Monday, January 13, 2003, at 10:14  PM, Dave Rolsky wrote:


 I _don't_ want to discuss implementation of this.  I want to talk 
about the API!

Agreed; I'm making this argument specifically because I think the 
proposed API is clearer.

Looking at the two alternatives, does the second really seem clearer?

   use DateTime;
   my $dt = DateTime->new( 'MySQL' => $mysql_dt );
   print $dt->to_string( 'MySQL' );

   use DateTime;
   use DateTime::Parse::MySQL;
   my $dt = DateTime->from_mysql_datetime( $mysql_dt );
   print $dt->to_mysql_string();


Um, yeah, the second is _much_ clearer.


Hmm... Really? To me, the first seems much clearer.

If this framework grows in the future, won't we end up with dozens of 
parser/formatter modules all stuffing methods into the base class?

And if someone wants to build a separate implementation of the DateTime 
interface, like the TAI64 code, how will they be able to integrate with 
those parsing/formatting modules, short of blindly making their code a 
subclass of the primary implementation?

If there's a public consensus that most people prefer stuffing methods 
into the base package rather than having a gateway interface that 
dynamically dispatches calls to other classes, I'll drop the issue, but 
it seems to me like a significant mistake.

And how is DateTime->new supposed to know about all the myriad 
parameters that would exist with your suggestion anyway?  If it finds 
an unknown parameter, should it call "DateTime::Parse->$param()"?

No, it would load a module named DateTime::Parse::$param, and then call 
a method on that class, eg DateTime::Parse::MySQL->parse_string().

And its less error prone as well! If I mis-type 'MySQL' as 'Mysql' 
then what is DateTime supposed to do?

If you mis-enter the name of a module, it would die with a message 
along the lines of "The $param format is unknown, and 
DateTime::Parse::$param can't be found in @INC; please check that 
you've written the format name correctly and that the associated module 
is installed on this host.";

What if a specific parser needs _two_ params?


Presumably it could accept an array-ref, or grab a list of arguments.


Your first option is not on the table.


Er, why not?


The options on the table are: [...] or
  use DateTime;
  use DateTime::Parse::MySQL;
  my $dt = DateTime::Parse::MySQL->new_datetime( $mysql_dt );
  print DateTime::Parse::MySQL->mysql_datetime( $dt );


That's a straw man -- AFAIK, nobody's suggesting this kind of API.


Frankly, I think the first one is a lot easier to use and makes more
sense.  It's the decorator pattern without the dispatching overhead!


I don't see the similarity to the decorator pattern.

Decorators are a dynamic composition of objects, nestable such that you 
can stick one decorator in front of another, and each one is provided 
by a different class and so has its own namespace and inheritance tree.
  http://web.media.mit.edu/~tpminka/patterns/Decorator.html

The proposed approach of having add-on modules stuff new methods into 
the core class's namespace lacks all of those qualities, and seems more 
 reminiscent to me of the "big ball of mud" pattern then it does of 
some kind of "optimized decorator".

-Simon



Re: Parser Interface (Was Re: Picking up the ball)

2003-01-13 Thread Dave Rolsky
On Mon, 13 Jan 2003, Matthew Simon Cavalletto wrote:

> >> What's the benefit of making this distinction between core and
> >> "other" formats?
> >
> > Because "core" parsing would be available simply by doing:
> >   use DateTime;
>
> We can move the parsing to format modules and load them automatically.

Sure, that's possible too.  The real question is whether or not parsing
requires anything beyond doing "use DateTime".

> > It's really a question of whether or not users must load another
> > module to do parsing, that's all.
>
> The suggestion on the table is that even the "core" parsing be placed
> in another package, but that this be transparent to end-users.

But that's not my concern.  I _don't_ want to discuss implementation of
this.  I want to talk about the API!

> > Actually, I have some ideas for this. [...] the parsing modules would
> > just add methods to the DateTime namespace.
>
> Ick -- what's the advantage of doing it this way?
>
> It strikes me as a lot more logical to keep those methods in their own
> namespace and simply call them when needed.
>
> Looking at the two alternatives, does the second really seem clearer?
>
>use DateTime;
>my $dt = DateTime->new( 'MySQL' => $mysql_dt );
>print $dt->to_string( 'MySQL' );
>
>use DateTime;
>use DateTime::Parse::MySQL;
>my $dt = DateTime->from_mysql_datetime( $mysql_dt );
>print $dt->to_mysql_string();

Um, yeah, the second is _much_ clearer.  And its less error prone as well!

If I mis-type 'MySQL' as 'Mysql' then what is DateTime supposed to do?
And how is DateTime->new supposed to know about all the myriad parameters
that would exist with your suggestion anyway?  If it finds an unknown
parameter, should it call "DateTime::Parse->$param()"?  What if a specific
parser needs _two_ params?

Your first option is not on the table.  The options on the table are:

  use DateTime;
  use DateTime::Parse::MySQL;
  my $dt = DateTime->from_mysql_datetime( $mysql_dt );
  print $dt->to_mysql_string();

or

  use DateTime;
  use DateTime::Parse::MySQL;
  my $dt = DateTime::Parse::MySQL->new_datetime( $mysql_dt );
  print DateTime::Parse::MySQL->mysql_datetime( $dt );

Frankly, I think the first one is a lot easier to use and makes more
sense.  It's the decorator pattern without the dispatching overhead!


-dave

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



Re: Parser Interface (Was Re: Picking up the ball)

2003-01-13 Thread David Wheeler
On Monday, January 13, 2003, at 11:51  AM, Dave Rolsky wrote:


Actually, I have some ideas for this.  Something like:

  use DateTime;
  use DateTime::Parse::MySQL;

  my $dt = DateTime->from_mysql_datetime( $mysql_dt );

So the parsing modules would just add methods to the DateTime 
namespace.

Ah, the decorator pattern made easy. This once again shows why many 
design patterns are almost meaningless in Perl. ;-)

David

--
David Wheeler AIM: dwTheory
[EMAIL PROTECTED] ICQ: 15726394
http://david.wheeler.net/  Yahoo!: dew7e
   Jabber: [EMAIL PROTECTED]



Re: Parser Interface (Was Re: Picking up the ball)

2003-01-13 Thread Matthew Simon Cavalletto
On Monday, January 13, 2003, at 02:51  PM, Dave Rolsky wrote:


On Mon, 13 Jan 2003, Matthew Simon Cavalletto wrote:


What's the benefit of making this distinction between core and 
"other" formats?

Because "core" parsing would be available simply by doing:
  use DateTime;


We can move the parsing to format modules and load them automatically.


It's really a question of whether or not users must load another 
module to do parsing, that's all.

The suggestion on the table is that even the "core" parsing be placed 
in another package, but that this be transparent to end-users.

   my $dt = DateTime->new( ICal => '20030113' );

   # Causes DateTime to load the ICal format module and request that
   # it parse the data and return it in a standard numeric form.


Actually, I have some ideas for this. [...] the parsing modules would 
just add methods to the DateTime namespace.

Ick -- what's the advantage of doing it this way?

It strikes me as a lot more logical to keep those methods in their own 
namespace and simply call them when needed.

Looking at the two alternatives, does the second really seem clearer?

  use DateTime;
  my $dt = DateTime->new( 'MySQL' => $mysql_dt );
  print $dt->to_string( 'MySQL' );

  use DateTime;
  use DateTime::Parse::MySQL;
  my $dt = DateTime->from_mysql_datetime( $mysql_dt );
  print $dt->to_mysql_string();

-Simon



Re: Parser Interface (Was Re: Picking up the ball)

2003-01-13 Thread Dave Rolsky
On Mon, 13 Jan 2003, Matthew Simon Cavalletto wrote:

> What's the benefit of making this distinction between core and "other"
> formats?

Because "core" parsing would be available simply by doing:

  use DateTime;

That's about it.

> Why not define a parser interface and include the basic formats as
> modules in the main distribution?

What distro it's in is not the issue.  It's really a question of whether
or not users must load another module to do parsing, that's all.

> This type of design should encourage separation of concerns, and help
> to avoid monolithic implementations -- the current DateTime::new sub is
> over 100 lines long... The overhead of one more method call seems like

It's over 100 lines cause it needs refactoring.  That's on my todo list.

>my $dt = DateTime->new( ICal => '20030113' );
>
># Causes DateTime to load the ICal format module and request that
># it parse the data and return it in a standard numeric form.
># Equivalent to the following:
>require DateTime::Format::ICal;
>my $dt = DateTime->new( rd_sec =>
>  DateTime::Format::ICal->parse_into_ratadie_and_seconds('20030113')
>);

Actually, I have some ideas for this.  Something like:

  use DateTime;
  use DateTime::Parse::MySQL;

  my $dt = DateTime->from_mysql_datetime( $mysql_dt );

So the parsing modules would just add methods to the DateTime namespace.


-dave

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