ISO vanilla class

I

Irving Kimura

It would be useful to have a generic, base class with a little bit
more functionality than UNIVERSAL. The purpose of this class would
be to eliminate tedious repetition when defining the constructor
and accessor methods of a generic hash-ref object. It would let
users specify what are the required and optional parameters for
the constructor (along with the default values for the optional
parameters), and would set up accessor methods (through AUTOLOAD)
for these parameters, and maybe others. These methods could be
overridden when the default behavior is inappropriate. So, defining
a new class could be as simple as something like

package Book;
use base Vanilla;

use constant required_params => 'title';
use constant optional_params => { author => [ anonymous ],
edition => 1,
isbn => '',
year => '',
publisher => '' };
use constant extra_accessors => 'id';


and one could immediately begin using this object like this:

use Book;

my $book_1 = Book->new('JR', { author => ['Gaddis, William'] });
my $book_2 = Book->new({ year => 2000 }); # triggers exception

print $book_1->author; # prints 'Gaddis, William'
print $book_1->edition(9); # prints '1' (previous value)
$book_1->city('New York'); # triggers exception

....etc. I haven't thought through all the facilities this vanilla
class would have, but something along these lines would be a nice
start.

Before I go off and reinvent the wheel, I thought that I'd ask if
anything like this already exists.

Thanks,

Irv
 
P

pkent

[generic base class with more functions]

Nice idea!

use Book;

my $book_1 = Book->new('JR', { author => ['Gaddis, William'] });
my $book_2 = Book->new({ year => 2000 }); # triggers exception

Personally I'd use a hash not a hash reference:

Book->new('Book title', Author => 'Gaddis, William);

And I'd not have that initial scalar, but simply:

Book->new( Title => 'title', Author => 'Author' );

Obviously the required parameters would be checked for, but I personally
prefer things to have names so there's a bit less to remember.

Personally I would, if you were going to do this, suggest some way of
declaring the types of things, so that you could say that 'title' was
both required and supposed to be a scalar. If someone put a hashref in
there it'd throw an error. Of course such constraints would be optional

print $book_1->author; # prints 'Gaddis, William'
print $book_1->edition(9); # prints '1' (previous value)
$book_1->city('New York'); # triggers exception

I think I prefer the explicit:

$book->getAuthor;
$book->setAuthor($value); # this would also have the type-checking
mentioned above

otherwise you will have a hard job setting a parameter to undef - how
can a get-and-set routine know whether:

$book->author;

means to retrieve the author or to set the author to undef? I like
explicit naming conventions. So you get more explicit method names
(they're just as easy to make in AUTOLOAD), and by prefixing them you
kind-of namespace the methods into get* and set* which will reduce the
possibilities of name clashes.

I'm sure there are other common things to put into this class too which
would be handy. Just my 2p.

P
 
T

Tassilo v. Parseval

Also sprach pkent:
I think I prefer the explicit:

$book->getAuthor;
$book->setAuthor($value); # this would also have the type-checking
mentioned above

otherwise you will have a hard job setting a parameter to undef - how
can a get-and-set routine know whether:

$book->author;

means to retrieve the author or to set the author to undef? I like
explicit naming conventions.

You can check the context. Void context would set the field, scalar or
list context retrieves it (in case of a defined parameter).

Tassilo
 
J

Jay Tilton

: It would be useful to have a generic, base class with a little bit
: more functionality than UNIVERSAL. The purpose of this class would
: be to eliminate tedious repetition when defining the constructor
: and accessor methods of a generic hash-ref object.

[snip]

: Before I go off and reinvent the wheel, I thought that I'd ask if
: anything like this already exists.

See if something in CPAN's Class:: hierarchy excites you.
Class::Accessor, Class::Struct, Class::MethodMaker,
Class::MakeMethods, Class::Contract, . . . .
 
J

J Krugman

In said:
I think I prefer the explicit:
$book->getAuthor;
$book->setAuthor($value); # this would also have the type-checking
mentioned above
otherwise you will have a hard job setting a parameter to undef - how
can a get-and-set routine know whether:

means to retrieve the author or to set the author to undef?

What about $book->author(undef) for setting the field to undef?

Irv
 
B

bill

In said:
See if something in CPAN's Class:: hierarchy excites you.
Class::Accessor, Class::Struct, Class::MethodMaker,
Class::MakeMethods, Class::Contract, . . . .

CPAN is great (and the CPAN module is God's gift to humanity), but
CPAN has one huge flaw. I don't know how to fix this flaw, but it
is very real: CPAN offers no way to distinguish the wheat from the
chaff. If you search CPAN for the keyword 'Class' you'll get 400+
hits. After 10-15 minutes of scanning this list, you may conclude
that 15-20 modules are relevant to your interest (and miss 1 or 2
you *should* be considering but aren't because their brief descriptions
did not ring your bell.) How to narrow down the field? Reading
the man pages for 20 modules, at 10 minutes per page, on average,
will take almost 3 hours. Assuming you got that far, you may have
narrowed the field down to 3-4 modules. To pick among these would
require programming with them for a while; you need to determine
the solidity of the code and the appositeness of the author's
high-level design. We are talking at least 1-2 days of solid work
here... I think this is probably an underestimate. This is
beginning to approach the time it would take to roll one's own,
which of course you'll do so brilliantly that you'll want to submit
it to CPAN, only to make it less likely that anyone will use either
yours or "competing" modules.

bill
 
C

Chris

pkent said:
[generic base class with more functions]

Nice idea!


use Book;

my $book_1 = Book->new('JR', { author => ['Gaddis, William'] });
my $book_2 = Book->new({ year => 2000 }); # triggers exception


Personally I'd use a hash not a hash reference:

Book->new('Book title', Author => 'Gaddis, William);

And I'd not have that initial scalar, but simply:

Book->new( Title => 'title', Author => 'Author' );

Obviously the required parameters would be checked for, but I personally
prefer things to have names so there's a bit less to remember.

Personally I would, if you were going to do this, suggest some way of
declaring the types of things, so that you could say that 'title' was
both required and supposed to be a scalar. If someone put a hashref in
there it'd throw an error. Of course such constraints would be optional


print $book_1->author; # prints 'Gaddis, William'
print $book_1->edition(9); # prints '1' (previous value)
$book_1->city('New York'); # triggers exception


I think I prefer the explicit:

$book->getAuthor;
$book->setAuthor($value); # this would also have the type-checking
mentioned above

otherwise you will have a hard job setting a parameter to undef - how
can a get-and-set routine know whether:

$book->author;

means to retrieve the author or to set the author to undef? I like
explicit naming conventions.

For accessors, I don't. The answer to your question "How?" is
demonstrated in the simplest of Perl OO tutorials just about everywhere.
When you write your accessor (a simple example that ignores the OP's
request for AUTOLOAD):

sub author {

my $self = shift;
$self->{author} = shift if (@_);
$self->{author};

}

Now you can:

$book->author( 'Larry Wall' );
print $book->author() . "\n";
(or even shorter is: print $book->author( 'Larry Wall' ) . "\n";
Sets and then gets all in one.)

Although I believe there are plenty of cases in the Class:: hierarchy to
choose from. I wrote my own base class module that does most of what
the OP wants, and it's VERY handy for creating objects on the fly with
automatic accessors via AUTOLOAD. Also works just like another poster
mentions -- just pass the hash:

my $obj1 = My::Object->new( Name => 'Thurston Howell', EMail => 'none' );
my $obj2 = My::Object->new( Hour => 12, Minute => 00, Second => 33 );

print $obj1->Name() . " " . $obj1->EMail() . "\n";
print $obj1->Name( 'Gilligan' ) . "\n";
print $obj2->Hour() . ":" . $obj2->Minute() . ":" $obj2->Second( 45 ) .
"\n";

Almost senseless uses here (as with most short examples), but in
programs, very powerful for creating base classes on the fly. Again,
the Class:: hierarchy is probably way better than my base class, but it
works for me.

Chris
 
J

James Willmore

CPAN is great (and the CPAN module is God's gift to humanity), but CPAN
has one huge flaw. I don't know how to fix this flaw, but it is very
real: CPAN offers no way to distinguish the wheat from the chaff. If
you search CPAN for the keyword 'Class' you'll get 400+ hits. After
10-15 minutes of scanning this list, you may conclude that 15-20 modules
are relevant to your interest (and miss 1 or 2 you *should* be
considering but aren't because their brief descriptions did not ring
your bell.) How to narrow down the field? Reading the man pages for 20
modules, at 10 minutes per page, on average, will take almost 3 hours.
Assuming you got that far, you may have narrowed the field down to 3-4
modules. To pick among these would require programming with them for a
while; you need to determine the solidity of the code and the
appositeness of the author's high-level design. We are talking at least
1-2 days of solid work here... I think this is probably an
underestimate. This is beginning to approach the time it would take to
roll one's own, which of course you'll do so brilliantly that you'll
want to submit it to CPAN, only to make it less likely that anyone will
use either yours or "competing" modules.

I usually go to http://search.cpan.org/ *first* and do a search. Some of
the things I look for are:

- complete documentation; if the author can't take the time to explain the
module's interface, then it's not worth my time to use it.

- history/changes; modules that have been around awhile and have been
updated over time are ones that will be around years from now.

- ease of use; if it takes an enormous effort on my part to get what I
want, then I might as well do it all myself. Modules are suppose to make
life easy, not complicated - I can do that on my own, thank you very much
;-)

- portable; what's the point of using some modules if the code isn't
portable. That's not to say *all* modules need to be portable. But given
the choice between one that is and one that isn't, I'll go for the
portable one every time.

- task-specific; no need to use a hammer when a fly swatter is in order
;-) If the module is so bloated with "stuff", then, again, I might as
well do it myself. Some modules allow you to import only those methods
you *need*, not the whole stinking thing into the namespace. Given a
choice between a module that allows *me* to decide what methods I want to
use versus one that doesn't, I'll use the one that does.

- word of mouth; nothing beats asking what others have used. Make sure
you get a well rounded view of the module and it's capabilities. Make
sure you get bad reviews - the evil known is better than the evil that's
unknown :)

Good modules to show what I'm talking about are:
CGI, DBI, LWP, Template Toolkit, Net::SMTP, and Net::FTP.

That's just a few tips for you when searching for "that special module" I
use. I hope you find these tips useful. It might cut your search time
down to about a day - depending on what you want to do ;-)

HTH

--
Jim

Copyright notice: all code written by the author in this post is
released under the GPL. http://www.gnu.org/licenses/gpl.txt
for more information.

a fortune quote ...
Law of the Perversity of Nature: You cannot successfully
<determine beforehand which side of the bread to butter.
 
B

bill

Thanks for your tips. I particularly like this one:

In said:
- word of mouth; nothing beats asking what others have used.

I totally agree. This is also the hardest tip to put to practice,
because when you ask around, like the OP did, almost invariably
the replies you'll get will be along the lines of "check out CPAN;
tons of stuff there", and you'll be back to square 1.

bill
 
A

Anno Siegel

Tassilo v. Parseval said:
Also sprach pkent:
You can check the context. Void context would set the field, scalar or
list context retrieves it (in case of a defined parameter).

I strongly disagree. Context should control what a sub returns, not what
it does. I consider other behavior unusual and cruel :)

In the case of accessors, divine intention wants the number of arguments
to control the behavior: "$book->author" retrieves the author, "book->
author( 'Mann')" sets it to "Mann", which it also returns, and "$book->
author( undef)" sets it to undef and returns undef. What could be more
logical (and straight-forward to code).

However, this disagreement, as well as others in this thread (which I
haven't even entirely read at this point) show why a module like the OP
describes doesn't exist, or, if it does, why it hasn't conquered the Perl
world. There are so many details in the interface to disagree about that,
with any particular implementation, there will be one detail for every
potential user to disagree with. Since the module doesn't do anything hard,
you'll end up writing your own.

Anno
 
A

Anno Siegel

bill said:
Thanks for your tips. I particularly like this one:

In <[email protected]> James Willmore


I totally agree. This is also the hardest tip to put to practice,
because when you ask around, like the OP did, almost invariably
the replies you'll get will be along the lines of "check out CPAN;
tons of stuff there", and you'll be back to square 1.

After looking at the documentation, I tend to look at the code rather early
("look" with CPAN, "z" with CPANPLUS). Bad code is pretty obvious, and
a distressing number of modules can be eliminated that way.

It also helps to look at authors' PAUSE directories. What else have they
written? Anything popular there? How do they maintain other modules?
(If a module hasn't been updated for a while, it may simply mean it's
stable.)

Otherwise, yes, finding a module on CPAN can be time-consuming. The
"insert-problem-description-here" machine is almost working now...

Anno
 
T

Tassilo v. Parseval

Also sprach Anno Siegel:
Tassilo v. Parseval said:
Also sprach pkent:


I strongly disagree. Context should control what a sub returns, not what
it does. I consider other behavior unusual and cruel :)

Just a matter of documenting it properly. :)

As a matter of fact I quickly realized that context is indeed not
necessary because you can always check whether @_ contains something
(even undef) or not. Had I thought about this (rather obvious) fact when
reading the OP, I wouldn't have made this questionable suggestion.
However, this disagreement, as well as others in this thread (which I
haven't even entirely read at this point) show why a module like the OP
describes doesn't exist, or, if it does, why it hasn't conquered the Perl
world. There are so many details in the interface to disagree about that,
with any particular implementation, there will be one detail for every
potential user to disagree with. Since the module doesn't do anything hard,
you'll end up writing your own.

If you ask me, I find most of the modules in the Class:: namespace
rather useless for the reasons you mentioned. Often I find they'd
require more reading of the docs than they could save later when writing
the code. In many cases they restrict Perl's flexibility and in doing so
they restrict me as well.

Tassilo
 
I

Iain Chalmers

bill <[email protected]> said:
Thanks for your tips. I particularly like this one:

In <[email protected]> James Willmore


I totally agree. This is also the hardest tip to put to practice,
because when you ask around, like the OP did, almost invariably
the replies you'll get will be along the lines of "check out CPAN;
tons of stuff there", and you'll be back to square 1.

Thats presumably because the usual assumption (and most likely, usually
correst assumption) is that the original poster _hasn't_ searched CPAN
yet.

A query along the lines of:

"I need a module to do foo. I found Class::Foo, Class::Foo::Simple,
Data::Bah, and Universal::FooBah on Cpan. Has anyone used any of these
(or any other alternatives)? Any hints as to which one works best?"

Would generate a significantly different type of response...

big
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top