How to use main:: data in modules?

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?

Answers


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.


Need Your Help

Unable to start activity - ComponentInfo error

java android runtimeexception

This are the errors I get when I try to start my app.

Embed JGraph in JFrame with YAML

swing graph jframe yaml

I'm starting to create a GUI with javabuilders in order to get more familiar with YAML and to implement some ideas.

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.