In script i initialize several handlers and set variables which should be available for functions in separate modules. Which is the best way to use them ($q, $dbh, %conf) in modules?
Example pseudo module:
package My::Module
sub SomeFunction (
#data = $dbh->selectrow_array("SELECT * FROM Foo WHERE Bar = ?", undef, $conf{Bar} );
return $q->p( "#data" );
)
1;
Example pseudo script:
use CGI;
use DBI;
use My::Module;
our $q = new CGI;
our $dbh = some_connenction_function($dsn);
our %conf = ( Foo => 1, Bar => 2, Random => some_dynamic_data() );
I understand that using main:: namespace will work, but there sholud be cleaner way? Or not?
package My::Module
Your modules should be independent of the context. That is, they shouldn't expect that $dbh is the database handler, or that they should return stuff in $q. or that configuration is kept in %conf.
For example, what if you suddenly find yourself with two instances of database handles? What do you do? I hate it when a module requires me to use module specific variables for configuration because it means I can't use two different instances of that module.
So you have two choices:
Either pass in the required data each time.
Create an object instance (that's right Object Oriented Programming) to store the required information.
Let's look at the first instance using your pseudo code:
sub someFunction (
%param = #_;
%conf = %{param{conf};
#data = $param{dbh}->selectrow_array(
"SELECT * FROM Foo WHERE Bar = ?", undef, $conf{Bar}
);
return $param{q}->p( "#data" );
)
1;
Example pseudo script:
use CGI;
use DBI;
use My::Module;
my $q = new CGI;
my $dbh = some_connenction_function($dsn);
my %conf = ( Foo => 1, Bar => 2, Random => some_dynamic_data() );
someFunction (
q => $q,
dbh => $dbh,
conf => \%conf,
);
Here I'm using parameter calls. Not too bad. Is it? Now if you need another select statement, you can use different variables.
Sure, but what if you don't want to keep passing variables all of the time. Well then, you can use an Object Oriented Techniques. Now, relax and calm down. There are many, many good reasons to use object oriented design:
It can simplify your programming: This confuses people because object oriented programming means thinking about how your program will work, then designing it, then creating the various objects. All you want to do is code and get it out of the way. The truth is that by thinking about your program and designing it makes your program work better, and you code faster. The design aspect keeps the complexity out of your main code and tucks it safely away in small, easily digestible routines.
It's what is cool in Perl: You're going to have to get use to object oriented Perl because that's what everyone else is writing. You'll be seeing lots of my $foo = Foo::Bar->new; type of statements. Newer Perl modules only have object oriented interfaces, and you won't be able to use them.
Chicks dig it: Hey, I'm just grasping at straws here...
Let's see how an object oriented approach might work. First, let's see the main program:
use CGI;
use DBI;
use My::Module;
my $q = new CGI;
my $dbh = some_connenction_function($dsn);
my %conf = ( Foo => 1, Bar => 2, Random => some_dynamic_data() );
my $mod_handle = My::Module->new (
q => $q,
dbh => $dbh,
conf => \%conf,
);
$mod_handle->someFunction;
In the above, I now create an object instance that contains these variables. And, magically, I've changed your Functions into Methods. A method is simply a function in your Class (aka module). The trick is that my instance (the variable $mod_handler has all of your required variables stored away nice and neat for you. The $mod_hander-> syntax merely passes this information for my into my functions I mean methods.
So, what does your module now look like? Let's look at the first part where I have the Constructor which is simply the function that creates the storage for my variables I need:
sub new {
my $class = shift;
my %param = #_;
my $self = {};
bless $self, $class
$self->{Q} = $q;
$self->{DBH} = $dbh;
$self->{CONF} = $conf;
return $self;
}
Let's look at the first thing that is a bit different: my $class = shift;. Where is this coming from? When I call a function with the syntax Foo->Bar, I am passing Foo as the first parameter in the function Bar. Thus, $class is equal to My::Module. It is the same as if I called your function this way:
my $mod_handle = My::Module::new("My::Module", %params);
instead of:
my $mod_handle = My::Module->new(%params);
The next thing is the my $self = {}; line. This is creating a reference to a hash. If you don't understand references, you should look at Mark's Reference Tutorial that's included in Perldocs. Basically, a reference is the memory location where data is stored. In this case, my hash doesn't have a name, all I have is a reference to the memory where it's stored called $self. In Perl, there's nothing special about the name new or $self, but they're standards that everyone pretty much follows.
The bless command is taking my reference, $self, and declaring it a type My::Module. That way, Perl can track whether $mod_handle is the type of instance that has access to these functions.
As you can see, the $self reference contains all the variables that my functions need. And, I conveniently pass this back to my main program where I store it in $mod_handle.
Now, let's look at my Methods:
sub SomeFunction {
$self = shift;
my $dbh = $self->{DBH};
my $q = $self->{Q};
my %conf = %{self->{CONF}};
#data = $dbh->selectrow_array(
"SELECT * FROM Foo WHERE Bar = ?", undef, $conf{Bar}
);
return $param{q}->p( "#data" );
}
Again, that $self = shift; line. Remember I'm calling this as:
$mod_handle->SomeFunction;
Which is the same as calling it:
My::Module::SomeFunction($mod_handle);
Thus, the value of $self is the hash reference I stored in $mod_handle. And, that hash reference contains the three values I am always passing to this function.
Conclusion
You should never share variables between your main program and your module. Otherwise, you're stuck not only with the same name in your program each and every time, but you must be careful not to use your module in parallel in another part of your program.
By using object oriented code, you can store variables you need in a single instance and pass them back and forth between functions in the same instance. Now, you can call the variables in your program whatever you want, and you can use your module in parallel instances. It improves your program and your programming skills.
Beside, you might as well get use to object oriented programming because it isn't going away. It works too well. Entire languages are designed to be exclusively object oriented, and if you don't understand how it works, you'll never improve your skills.
And, did I mention chicks dig it?
Adium
Before all the Perl hackers descend upon me. I want to mention that my Perl object oriented design is very bad. It's way better than what you wanted, but there is a serious flaw in it: I've exposed the design of my object to all the methods in my class. That means if I change the way I store my data, I'll have to go through my entire module to search and replace it.
I did it this way to keep it simple, and make it a bit more obvious what I was doing. However, as any good object oriented programmer will tell you (and second rate hacks like me) is that you should use setter/getter functions to set your member values.
A setter function is pretty simple. The template looks like this:
sub My_Method {
my $self = shift;
my $value = shift;
# Something here to verify $value is valid
if (defined $value) {
$self->{VALUE} = $value;
}
return $self->{VALUE};
}
If I call $instance->My_Method("This is my value"); in my program, it will set $self->{VALUE} to This is my value. At the same time, it returns the value of $self->{VALUE}.
Now, let's say I all it this way:
my $value = $instance->My_Method;
My parameter, $value is undefined, so I don't set the value $self->{VALUE}. However, I still return the value anyway.
Thus, I can use that same method to set and get my value.
Let's look at my Constructor (which is a fancy name for that new function):
sub new {
my $class = shift;
my %param = #_;
my $self = {};
bless $self, $class
$self->{Q} = $q;
$self->{DBH} = $dbh;
$self->{CONF} = $conf;
return $self;
}
Instead of setting the $self->{} hash reference directly in this program, good design said I should have used getter/setter functions like this:
sub new {
my $class = shift;
my %param = #_;
my $self = {};
bless $self, $class
$self->Q = $q; #This line changed
$self->Dbh = $dbh; #This line changed
$self->Conf = $conf; #This line changed
return $self;
}
Now, I'll have to define these three subroutines, Q, Dbh, and Conf, but now my SomeFunction method goes from this:
sub SomeFunction {
$self = shift;
my $dbh = $self->{DBH};
my $q = $self->{Q};
my %conf = %{self->{CONF}};
#data = $dbh->selectrow_array(
"SELECT * FROM Foo WHERE Bar = ?", undef, $conf{Bar}
);
return $param{q}->p( "#data" );
}
To this:
sub SomeFunction {
$self = shift;
my $dbh = $self->Dbh; #This line changed
my $q = $self->Q; #This line changed
my %conf = %{self->Conf}; #This line changed
#data = $dbh->selectrow_array(
"SELECT * FROM Foo WHERE Bar = ?", undef, $conf{Bar}
);
return $param{q}->p( "#data" );
}
The changes are subtle, but important. Now my new function and my SomeFunction have no idea how these parameters are stored. The only place that knows how they're stored is the getter/setter function itself. If I change the class data structure, I don't have to modify anything but the getter/setter functions themselves.
Postscript
Here's food for thought...
If all of your SQL calls are in your My::Module function, why not simply initialize the $dbh, and the $q there in the first place. This way, you don't need to include the Use Dbi; module in your program itself. In fact, your program now remains blissfully ignorant exactly how the data is stored. You don't know if it's a SQL database, a Mongo database, or even some flat Berkeley styled db structure.
I'm including a module I did for a job long, long ago where I tried to simplify the way we use our database. This module did several things:
It handled everything about the database. The initialization, and all the handles. Thus, your main program didn't have to use any module but this.
It also moved away from the developer writing select statements. Instead, you defined what fields you wanted, and it figured out how to do the query for you.
It returns an incriminator function that's used to fetch the next row from the database.
Take a look at it. It's not the greatest, but you'll see how I use object oriented design to remove all of the various issues you are having. To see the documentation, simply type in perldoc MFX:Cmdata on the command line.
Using main:: explicitly is perfectly clean
As an alternative, you can pass that data into the module constructor method assuming your module is object based (or copy it into module's own variables from main:: in the constructor). This way the not-quite-perfwectly-pretty main:: is hidden away from the rest of the module.
One cleaner way is to use Exporter to make symbols from other namespaces available in your package. If you are just an occasional Perl programmer, I wouldn't bother with it because there's a bit of a learning curve to it, there are lots of gotchas, and for a toy project it makes the code even more complex. But it is essential for larger projects and for understanding other people's modules.
Usually, there are global variables (or especially global functions) in a package that you want to use in a different module without qualifying it (i.e., prepending package:: to every variable and function call). Here's one way that Exporter might be used to do that:
# MyModule.pm
package MyModule;
use strict; use warnings;
use Exporter;
our #EXPORT = qw($variable function);
our $variable = 42; # we want this var to be used somewhere else
sub function { return 19 }; # and want to call this function
...
1;
# my_script.pl
use MyModule;
$variable = 16; # refers to $MyModule::variable
my $f = function(); # refers to &MyModule::function
Your problem spec is backwards (not that there's necessarily anything wrong with that) -- you want variables in the main script and main package to be visible inside another module. For a short list of variables/functions that are used many times, a cleaner way to do that might be to hack at the symbol table:
package My::Module;
# required if you use strict . You do use strict , don't you?
our ($q, $dbh, %conf);
*q = \$main::q;
*dbh = \$main::dbh;
*conf = \%main::conf;
...
Now $My::Module::q and $main::q refer to the same variable, and you can just use $q in either the main or the My::Module namespace.
Related
I'm having an issue with a recent code review. I've been advised to change the following function call:
storeShmcoreservJobsLogs(
$self->{'shmJobDetails'},
$self->{'nhcJobDetails'},
$self->{'cppDetails'},
$self->{'siteId'},
$neTypesIdMap,
$dbh
);
To only use two arguments, being $self and $dbh. So I have coded as follows
storeShmcoreservJobsLogs($self, $dbh);
And the function signature as follows:
sub storeShmcoreservJobsLogs($$) {
my($self, $dbh) = #_;
if ( $#{$self->$shmJobDetails} > -1 ) {
The if statement unfortunately throws an error with the value of $shmJobDetails when I test the change
Global symbol "$shmJobDetails" requires explicit package name at /data/ddp/current/analysis/TOR/elasticsearch/handlers/misc/Shm.pm line 148.
So I must have misinterpreted the instruction. Is anything obvious wrong?
There's no variable $shmJobDetails so you get the compilation error. Do the same thing that you were doing before:
sub storeShmcoreservJobsLogs {
my($self,$dbh)=#_;
if ( $#{ $self->{'shmJobDetails'} } > -1 ) {
Now you're passing the complete object and the subroutine can use any part of the object it needs.
You might want to make some object methods to answer the questions you'll ask it instead of accessing its internals. That method can do all the work to figure out true or false:
sub storeShmcoreservJobsLogs {
my($self,$dbh)=#_;
if ( $self->has_jobs ) {
The use of a lexical variable called $self implies that you're using object-oriented methods, but your code is far from being object-oriented
Are you sure that you understand the points being made in the code review? It's looking like you're writing a method, and the fields should be extracted from the hash within the method
The method definition should be more like this
sub store_shmcoreserv_jobs_logs {
my $self = shift;
my ($id_map, $dbh) = #_;
my #fields = #{$self}{qw/ shmJobDetails nhcJobDetails cppDetails siteId /};
...
while the call should look like this
$self->storeShmcoreservJobsLogs($neTypesIdMap, $dbh)
All of this is essential to Perl object-oriented programming. You should study perlobj together with the rest of the Perl language reference
My program creates an object, which, in turn, creates another object
MainScript.pm
use module::FirstModule qw ($hFirstModule);
$hFirstModule->new(parametres);
$hFirstModule->function();
FirstModule.pm
use Exporter ();
#EXPORT = qw($hFirstModule);
use module::SecondModule qw ($hSecondModule);
sub new {
my $className = shift;
my $self = { key => 'val' };
bless $self, $classname;
return $self;
}
sub function{
$hSecondModule->new(parametres);
#some other code here
}
I want to acces $hSecondModule from MainScript.pm.
It depends.
We would have to see the actual code. What you've shown is a bit ambiguous. However, there are two scenarios.
You can't
If your code is not exactly like what you have shown as pseudo-code, then there is no chance to do that. Consider this code in &module1::function.
sub function {
my $obj = Module2->new;
# ... more stuff
return;
}
In this case, you are not returning anything, and the $obj is lexically scoped. A lexical scope means that it only exists inside of the closest {} block (and all blocks inside that). That's the block of the function sub. Once the program returns out of that sub, the variable goes out of scope and the object is destroyed. There is no way to get to it afterwards. It's gone.
Even if it was not destroyed, you cannot reach into a different scope.
You can
If you however return the object from the function, then you'd have to assign it in your script, and then you can access it later. If the code is exactly what you've shown above, this works.
sub function {
my $obj = Module2->new;
# nothing here
}
In Perl, subs always return the last true statement. If you don't have a return and the last statement is the Module2->new call, then the result of that statement, which is the object, is returned. Of course it also works if you actually return explicitly.
sub function {
return Module2->new;
}
So if you assign that to a variable in your script, you can access it in the script.
my $obj = module1->function();
This is similar to the factory pattern.
This is vague, but without more information it's impossible to answer the question more precicely.
Here is a very hacky approach that takes your updated code into consideration. It uses Sub::Override to grab the return value of the constructor call to your SecondModule thingy. This is something that you'd usually maybe do in a unit test, but not in production code. However, it should work. Here's an example.
Foo.pm
package Foo;
use Bar;
sub new {
return bless {}, $_[0];
}
sub frobnicate {
Bar->new;
return;
}
Bar.pm
package Bar;
sub new {
return bless {}, $_[0];
}
sub drink {
return 42; # because.
}
script.pl
package main;
use Foo; # this will load Bar at compile time
use Sub::Override;
my $foo = Foo->new;
my $bar; # this is lexical to the main script, so we can use it inside
my $orig = \&Bar::new; # grab the original function
my $sub = Sub::Override->new(
"Bar::new" => sub {
my $self = shift;
# call the constructor of $hSecondModule, grab the RV and assign
# it to our var from the main script
$bar = $self->$orig(#_);
return $bar;
}
);
$foo->frobnicate;
# restore the original sub
$sub->restore;
# $bar is now assigend
print $bar->drink;
Again, I would not do this in production code.
Let's take a look at the main function. It first creates a new Foo object. Then it grabs a reference to the Bar::new function. We need that as the original, so we can call it to create the object. Then we use Sub::Override to temporarily replace the Bar::new with our sub that calls the original, but takes the return value (which is the object) and assigns it to our variable that's lexical to the main script. Then we return it.
This function will now be called when $foo->frobnicate calls Bar->new. After that call, $bar is populated in our main script. Then we restore Bar::new so we don't accidentally overwrite our $bar in case that gets called again from somewhere else.
Afterwards, we can use $bar.
Note that this is advanced. I'll say again that I would not use this kind of hack in production code. There is probably a better way to do what you want. There might be an x/y problem here and you need to better explain why you need to do this so we can find a less crazy solution.
I have come across code with the following syntax:
$a -> mysub($b);
And after looking into it I am still struggling to figure out what it means. Any help would be greatly appreciated, thanks!
What you have encountered is object oriented perl.
it's documented in perlobj. The principle is fairly simple though - an object is a sort of super-hash, which as well as data, also includes built in code.
The advantage of this, is that your data structure 'knows what to do' with it's contents. At a basic level, that's just validate data - so you can make a hash that rejects "incorrect" input.
But it allows you to do considerably more complicated things. The real point of it is encapsulation, such that I can write a module, and you can make use of it without really having to care what's going on inside it - only the mechanisms for driving it.
So a really basic example might look like this:
#!/usr/bin/env perl
use strict;
use warnings;
package MyObject;
#define new object
sub new {
my ($class) = #_;
my $self = {};
$self->{count} = 0;
bless( $self, $class );
return $self;
}
#method within the object
sub mysub {
my ( $self, $new_count ) = #_;
$self->{count} += $new_count;
print "Internal counter: ", $self->{count}, "\n";
}
package main;
#create a new instance of `MyObject`.
my $obj = MyObject->new();
#call the method,
$obj->mysub(10);
$obj->mysub(10);
We define "class" which is a description of how the object 'works'. In this, class, we set up a subroutine called mysub - but because it's a class, we refer to it as a "method" - that is, a subroutine that is specifically tied to an object.
We create a new instance of the object (basically the same as my %newhash) and then call the methods within it. If you create multiple objects, they each hold their own internal state, just the same as it would if you created separate hashes.
Also: Don't use $a and $b as variable names. It's dirty. Both because single var names are wrong, but also because these two in particular are used for sort.
That's a method call. $a is the invocant (a class name or an object), mysub is the method name, and $b is an argument. You should proceed to read perlootut which explains all of this.
Assume the following code:
package Thing;
sub new {
my $this=shift;
bless {#_},$this;
}
sub name {
my $this=shift;
if (#_) {
$this->{_name}=shift;
}
return $this->{_name};
}
Now assume we've instantiated an object thusly:
my $o=Thing->new();
$o->name('Harold');
Good enough. We could also instantiate the same thing more quickly with either of the following:
my $o=Thing->new(_name=>'Harold'); # poor form
my $o=Thing->new()->name('Harold');
To be sure, I allowed attributes to be passed in the constructor to allow "friendly" classes to create objects more completely. It could also allow for a clone-type operator with the following code:
my $o=Thing->new(%$otherthing); # will clone attrs if not deeper than 1 level
This is all well and good. I understand the need for hiding attributes behind methods to allow for validation, etc.
$o->name; # returns 'Harold'
$o->name('Fred'); # sets name to 'Fred' and returns 'Fred'
But what this doesn't allow is easy manipulation of the attribute based on itself, such as:
$o->{_name}=~s/old/ry/; # name is now 'Harry', but this "exposes" the attribute
One alternative is to do the following:
# Cumbersome, not syntactically sweet
my $n=$o->name;
$n=~s/old/ry/;
$o->name($n);
Another potential is the following method:
sub Name :lvalue { # note the capital 'N', not the same as name
my $this=shift;
return $this->{_name};
}
Now I can do the following:
$o->Name=~s/old/ry/;
So my question is this... is the above "kosher"? Or is it bad form to expose the attribute that way? I mean, doing that takes away any validation that might be found in the 'name' method. For example, if the 'name' method enforced a capital first letter and lowercase letters thereafter, the 'Name' (capital 'N') bypasses that and forces the user of the class to police herself in the use of it.
So, if the 'Name' lvalue method isn't exactly "kosher" are there any established ways to do such things?
I have considered (but get dizzy considering) things like tied scalars as attributes. To be sure, it may be the way to go.
Also, are there perhaps overloads that may help?
Or should I create replacement methods in the vein of (if it would even work):
sub replace_name {
my $this=shift;
my $repl=shift;
my $new=shift;
$this->{_name}=~s/$repl/$new/;
}
...
$o->replace_name(qr/old/,'ry');
Thanks in advance... and note, I am not very experienced in Perl's brand of OOP, even though I am fairly well-versed in OOP itself.
Additional info:
I guess I could get really creative with my interface... here's an idea I tinkered with, but I guess it shows that there really are no bounds:
sub name {
my $this=shift;
if (#_) {
my $first=shift;
if (ref($first) eq 'Regexp') {
my $second=shift;
$this->{_name}=~s/$first/$second/;
}
else {
$this->{_name}=$first;
}
}
return $this->{_name};
}
Now, I can either set the name attribute with
$o->name('Fred');
or I can manipulate it with
$o->name(qr/old/,'ry'); # name is now Harry
This still doesn't allow stuff like $o->name.=' Jr.'; but that's not too tough to add. Heck, I could allow calllback functions to be passed in, couldn't I?
Your first code example is abolutely fine. This is a standard method to write accessors. Of course this can get ugly when doing a substitution, the best solution might be:
$o->name($o->name =~ s/old/ry/r);
The /r flag returns the result of the substitution. Equivalently:
$o->name(do { (my $t = $o->name) =~ s/old/ry/; $t });
Well yes, this 2nd solution is admittedly ugly. But I am assuming that accessing the fields is a more common operation than setting them.
Depending on your personal style preferences, you could have two different methods for getting and setting, e.g. name and set_name. (I do not think get_ prefixes are a good idea – 4 unneccessary characters).
If substituting parts of the name is a central aspect of your class, then encapsulating this in a special substitute_name method sounds like a good idea. Otherwise this is just unneccessary ballast, and a bad tradeoff for avoiding occasional syntactic pain.
I do not advise you to use lvalue methods, as these are experimental.
I would rather not see (and debug) some “clever” code that returns tied scalars. This would work, but feels a bit too fragile for me to be comfortable with such solutions.
Operator overloading does not help with writing accessors. Especially assignment cannot be overloaded in Perl.
Writing accessors is boring, especially when they do no validation. There are modules that can handle autogeneration for us, e.g. Class::Accessor. This adds generic accessors get and set to your class, plus specific accessors as requested. E.g.
package Thing;
use Class::Accessor 'antlers'; # use the Moose-ish syntax
has name => (is => 'rw'); # declare a read-write attribute
# new is autogenerated. Achtung: this takes a hashref
Then:
Thing->new({ name => 'Harold'});
# or
Thing->new->name('Harold');
# or any of the other permutations.
If you want a modern object system for Perl, there is a row of compatible implementations. The most feature-rich of these is Moose, and allows you to add validation, type constraints, default values, etc. to your attributes. E.g.
package Thing;
use Moose; # this is now a Moose class
has first_name => (
is => 'rw',
isa => 'Str',
required => 1, # must be given in constructor
trigger => \&_update_name, # run this sub after attribute is set
);
has last_name => (
is => 'rw',
isa => 'Str',
required => 1, # must be given in constructor
trigger => \&_update_name,
);
has name => (
is => 'ro', # readonly
writer => '_set_name', # but private setter
);
sub _update_name {
my $self = shift;
$self->_set_name(join ' ', $self->first_name, $self->last_name);
}
# accessors are normal Moose methods, which we can modify
before first_name => sub {
my $self = shift;
if (#_ and $_[0] !~ /^\pU/) {
Carp::croak "First name must begin with uppercase letter";
}
};
The purpose of class interface is to prevent users from directly manipulating your data. What you want to do is cool, but not a good idea.
In fact, I design my classes, so even the class itself doesn't know it's own structure:
package Thingy;
sub new {
my $class = shift;
my $name = shift;
my $self = {};
bless, $self, $class;
$self->name($name);
return $self;
}
sub name {
my $self = shift;
my $name = shift;
my $attribute = "GLUNKENSPEC";
if ( defined $name ) {
$self->{$attribute} = $name;
}
return $self->{$attribute};
}
You can see by my new constructor that I could pass it a name for my Thingy. However, my constructor doesn't know how I store my name. Instead, it merely uses my name method to set the name. As you can see by my name method, it stores the name in an unusual way, but my constructor doesn't need to know or care.
If you want to manipulate the name, you have to work at it (as you showed):
my $name = $thingy->name;
$name =~ s/old/ry/;
$thingy->name( $name );
In fact, a lot of Perl developers use inside out classes just to prevent this direct object manipulation.
What if you want to be able to directly manipulate a class by passing in a regular expression? You have to write a method to do this:
sub mod_name {
my $self = shift;
my $pattern = shift;
my $replacement = shift;
if ( not defined $replacement ) {
croak qq(Some basic error checking: Need pattern and replacement string);
}
my $name = $self->name; # Using my name method for my class
if ( not defined $name ) {
croak qq(Cannot modify name: Name is not yet set.);
}
$name = s/$pattern/$replacement/;
return $self->name($name);
}
Now, the developer can do this:
my $thingy->new( "Harold" );
$thingy->mod_name( "old", "new" );
say $thingy->name; # Says "Harry"
Whatever time or effort you save by allowing for direct object manipulation is offset by the magnitude of extra effort it will take to maintain your program. Most methods don't take more than a few minutes to create. If I suddenly got an hankering to manipulate my object in a new and surprising way, it's easy enough to create a new method to do this.
1. No. I don't actually use random nonsense words to protect my class. This is purely for demo purposes to show that even my constructor doesn't have to know how methods actually store their data.
I understand the need for hiding attributes behind methods to allow for validation, etc.
Validation is not the only reason, although it is the only one you refer to. I mention this because another is that encapsulation like this leaves the implementation open. For example, if you have a class which needs to have a string "name" which can be get and set, you could just expose a member, name. However, if you instead use get()/set() subroutines, how "name" is stored and represented internally doesn't matter.
That can be very significant if you write bunches of code with uses the class and then suddenly realize that although the user may be accessing "name" as a string, it would be much better stored some other way (for whatever reason). If the user was accessing the string directly, as a member field, you now either have to compensate for this by including code that will change name when the real whatever is changed and...but wait, how can you then compensate for the client code that changed name...
You can't. You're stuck. You now have to go back and change all the code that uses the class -- if you can. I'm sure anyone who has done enough OOP has run into this situation in one form or another.
No doubt you've read all this before, but I'm bringing it up again because there are a few points (perhaps I've misunderstood you) where you seem to outline strategies for changing "name" based on your knowledge of the implementation, and not what was intended to be the API. That is very tempting in perl because of course there is no access control -- everything is essential public -- but it is still a very very bad practice for the reason just described.
That doesn't mean, of course, that you can't simply commit to exposing "name" as a string. That's a decision and it won't be the same in all cases. However, in this particular case, if what you are particularly concerned with is a simple way to transform "name", IMO you might as well stick with a get/set method. This:
# Cumbersome, not syntactically sweet
Maybe true (although someone else might say it is simple and straightforward), but your primary concern should not be syntactic sweetness, and neither should speed of execution. They can be concerns, but your primary concern has to be design, because no matter how sweet and fast your stuff is, if it is badly designed, it will all come down around you in time.
Remember, "Premature optimization is the root of all evil" (Knuth).
So my question is this... is the above "kosher"? Or is it bad form to expose the attribute that way?
It boils down to: Will this continue to work if the internals change? If the answer is yes, you can do many other things including but not limited to validation.)
The answer is yes. This can be done by having the method return a magical value.
{
package Lvalue;
sub TIESCALAR { my $class = shift; bless({ #_ }, $class) }
sub FETCH { my $self = shift; my $m = $self->{getter}; $self->{obj}->$m(#_) }
sub STORE { my $self = shift; my $m = $self->{setter}; $self->{obj}->$m(#_) }
}
sub new { my $class = shift; bless({}, $class) }
sub get_name {
my ($self) = #_;
return $self->{_name};
}
sub set_name {
my ($self, $val) = #_;
die "Invalid name" if !length($val);
$self->{_name} = $val;
}
sub name :lvalue {
my ($self) = #_;
tie my $rv, 'Lvalue', obj=>$self, getter=>'get_name', setter=>'set_name';
return $rv;
}
my $o = __PACKAGE__->new();
$o->name = 'abc';
print $o->name, "\n"; # abc
$o->name = ''; # Invalid name
I think I read somewhere that some modules only have object oriented interfaces ( though they didn't create objects, they only held utility functions ). Is there a point to that?
First, its important to remember that in Perl, classes are implemented in a weird way, via packages. Packages also serve for general namespace pollution prevention.
package Foo;
sub new {
my ($class) = #_;
my $self = bless {}, $class;
return $self;
}
1;
That is how you make a Foo class in Perl (which can have an objected instantiated by calling Foo->new or new Foo). The use of new is just a convention; it can be anything at all. In fact, that new is what C++ would call a static method call.
You can easily create packages that contain only static method calls, and I suspect this is what you're referring to. The advantage here is that you can still use OO features like inheritance:
package Bar;
sub DoSomething {
my ($class, $arg) = #_;
$class->Compute($arg);
}
sub Compute {
my ($class, $arg) = #_;
$arg * 2;
}
1;
package Baz;
#Baz::ISA = qw(Bar);
sub Compute {
my ($class, $arg) = #_;
$arg * 2 - 1
}
1;
Given that, then
say Bar->DoSomething(3) # 6
say Baz->DoSomething(3) # 5
In fact, you can even use variables for the class name, so these can function very much like singletons:
my $obj = "Baz"; # or Baz->new could just return "Baz"
print $obj->DoSomething(3) # 5
[Code is untested; typos may be present]
I suspect that this is mostly a philosophical choice on the part of authors who prefer OO to imperative programming. Others have mentioned establishing a namespace, but it's the package that does that, not the interface. OO is not required.
Personally, I see little value in creating classes that are never instantiated (i.e. when there's no object in object-oriented). Perl isn't Java; you don't have to write a class for everything. Some modules acknowledge this. For example: File::Spec has an OO interface but also provides a functional interface via File::Spec::Functions.
File::Spec also provides an example of where OO can be useful for uninstantiated "utility" interfaces. Essentially, File::Spec is an abstract base class -- an interface with no implementation. When you load File::Spec it checks which OS you're using and loads the appropriate implementation. As a programmer, you use the interface (e.g. File::Spec->catfile) without having to worry about which version of catfile (Unix, Windows, VMS, etc.) to actually call.
As others have said, inheritance is the big gain if an actual object is not needed. The only thing I have to add here is the advice to name your variables well when writing such interfaces, e.g.:
package Foo;
# just a static method call
sub func
{
my $class = shift;
my (#args) = #_;
# stuff...
}
I named the variable that holds the classname "$class", rather than $this, to make it clear to subsequent maintainers that func() will be called as Foo->func() rather than $foo->func() (with an instantiated Foo object). This helps avoid someone adding this line later to the method:
my $value = $this->{key};
...which will fail, as there is no object to deference to get the "key" key.
If a method might be called either statically or against an instantiated object (for example, when writing a custom AUTOLOAD method), you can write this:
my method
{
my $this = shift;
my $class = ref($this) || $this;
my (#args) = #_;
# stuff...
}
namespacing, mostly. Why not? Everything that improves perl has my full approval.