Re: Parser Interface (Was Re: Picking up the ball)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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 ===*/