"A quick and easy intrOO, part II" Thursday, October 04, 2001 Copyright Tommy Butler, 2001 Picking up on where we left off in tutorial one... [Q] Does the fact that you use modules such as CGI automatically make your scripts object oriented? I haven't been using the same syntax (the arrow operator '->') to use the CGI module. use CGI qw(param); my($data) = param('data'); I haven't explicitly created a new object here. Does this mean that no bject has been created? I would guess that this is not object oriented. [A] Good question. This concept wasn't explained in the last tutorial because everybody needed to understand the concept of 'packages', or what some people prefer to call 'namespaces'. After covering this concept we'll come back and answer that question directly. Now, remember how I was talking about needing to show Perl where to go in order to find the object methods and attributes via references to the object? Great, you see when you obtain that reference you've actually got your hands on a shortcut of sorts, to the fully qualified Perl address of that module's package or namespace. [Q] So what the heck does that mean? In english Please? [A] Alright. Getting right down to the nitty-gritty, we have to understand the way Perl sets up what I'll call it's addressing system. In most neighborhoods around the world, you can find a person in his house by following the details of his address from the most general identifier, to the most specific. For example, you get to me in my company's offices by following the details of this address: Tommy Butler Suite 307 2200 N Lamar Dallas, TX 75202 USA What you'd do to find me, based on that address, would be to first start looking in the United States of America. If you looked for my street in India, perhaps it would exist -- but that doesn't mean you'll find me. So making sure you first were in the right country, you'd have to make sure you were then looking for me in the right State, Texas. Once in Texas, you could narrow down your search a quite a bit my looking in the right postal district, zip code 75202. That would immediately allow you to find out that I'm in downtown Dallas, somewhere at the west end. From there it would be easy to find my street, North Lamar, and then you'd simply have to find the building with a specific number on it, 75202. Wow, you're there! The White Swan building, an old coffee factory, rebuilt in '83 and leased out to companies for office space. Cool. Now you just come inside, and noting the number of my company's suite, you're likely to realize we're located on the 3rd floor. Just hop in the elevator and come on up. Around the corner is our office, "Internet Stategies, Inc." Come on in and have a Dr. Pepper on me. You see, we basically worked our way backwards from the most general element in my address to the most specific. It's the same way in any object oriented language I know. You start at the top and work your way down. An example of Perl's addressing system for variables, routines, filehandles, etc looks like this, the most general element appearing first, working our way in: $Package_Name::Variable_Name -[or]- @Package_name::Sub_Class_Name::Another_Sub_Class_Name::Array_Name; -[or]- Package_Name::subroutine( [argment list] ); -[or]- print Package_Name::Filehandle $this_random_string; [Q] Cool, I think I'm starting to get that addressing thingy. So it's kind of like using a variable's full name, or fully-qualified name instead of it's first name only, right? [A] Exactly, only instead of seperating the individual elements of a Perl "address" to the variable, routine, filehandle, etc with spaces, we use two colons in succession between the names as seperators instead. Don't ask me why, mabe Larry Wall decided it looked like a camel's footprints while walking between one part of a fully qualified name to the next. ('::') Probably not, though ;o) [Q] Alright, so how does an object reference act as a shortcut to a fully qualified name for the stuff in my modules? [A] Well, if you were to look at that reference with X-ray vision, you'd find that the variable which holds it contains the full name of your object's namespace inside. [Q] Wow! That sounds really phat, so what exactly does it mean? [A] Let's try to look at it from a visual point of view: Package "main" Packagee "CGI" __________________ _________________________________ | Your script + | | | | its variables | | Now when you "use" a module | | and subroutines | | in your script, like | | live in here. | | | | let's use CGI; |---->| use CGI; | |__________________| | | The full names | You are telling Perl to come | of your subroutines | and find all the stuff in the | are really something | package named "CGI", or | like: -+ | everything over here in this | | | box more or less.* | | |_________________________________| | | sub main::sting2int { +-----> my($string); return(int($string}); } And the full names of the subroutines and global variables in the CGI package (or 'namespace') look like this: CGI::param() # this is a call to the CGI method named param, # or in other words, to the subroutine named # "sub param" in the CGI.pm module $CGI::version # this is the global variable (formally called a # "package variable" in Perl for reasons we'll # explain later on. Notice how the dollar sign '$' # comes first, instead of right before "version" @CGI::ISA # here's the name of an array you're sure to find # somewhere near the top of CGI.pm The syntax to # access it is just the same, where the '@' comes # first, instead of before "ISA" [Q] *Ok, so where does it look then, where's the "CGI" namespace? [A] Well Perl is going to look in your script first, to see if you included in your script a directive to switch over from the "main" namespace, to the "CGI" namespace. In other words, you can switch over from one package name to another just like is shown in this next example. But if Perl can't find the namespace designated by the word you type in after the use() command, it goes and starts looking for files in it's default include directories that have that name. When it finds one, it makes a class out of it for you. Otherwise you will get a nasty error saying that Perl couldn't find a file with that namespace, so you better fix it by putting a file with that name inside it's include directories (listed in the special variable called @INC available in all namespaces, like %ENV). If you don't have administrative permissions needed to put your module in one of Perl's default include directories, then tell it that you want it to use one of your private module directories to find the module. You do this by saying: use lib '/name/of/your/module/directory/here'; Then you won't get that ugly error. Ok then, now let's see how to switch from one package name to another right in the same file! #!/usr/bin/perl # start of your script # I'm bored with 'main', so let's switch # over to a different package name now... package Tommy; sub get_my_name { my($name) = __PACKAGE__; return($name); } # ok, enough of this, let's get back to # my script and stop fooling around... package main; # we are now back in the same namespace as the main script, # but we can still access the stuff over there in package # 'Tommy' if we use a fully qualified Perl address to do it... # (returns 'Tommy') my($best_friend) = Tommy::get_my_name(); # otherwise, if you just try something like what is shown below # to get to that subroutine over in package 'Tommy', you'll cause # a fatal error. That's because Perl will always assume that if you # don't use a fully qualified address to a subroutine, var, etc # that you are talking about the CURRENT namespace or package... my($stupid_error) = get_my_name(); # ERROR! ERROR! [Q] So you're telling me that my script has it's own package name, or it's own namespace? How? I din't tell Perl to do that anywhere in my script, at least I don't think so. [A] Even if you don't specifically declare package main; at the beginning of your script, Perl defaults to it. It's just a special rule that only the coolest Perl hackers ever know about. Otherwise, you couldn't ever get a hold of things in your main script from inside the modules you create, and sometimes you might really want to. So if you do, just prefix the subroutine name, or package variable which you want from your script like this: %main::configuration; @main::script_parameters; @main::ARGV; [Q] So about these so-called 'package variables', what are they exactly? are they different than the ones you make with a declaration like: my($foo); [A] Package variables are different, than the one's you declare anywere, in modules or in your script, with my(); [Q] Why? [A] Because they are truly global, whereas the variables you create with my() are called 'lexical variables'. Lexical variables don't really belong to a package. They only exist inside the code block you made them in. If you make a variable called "$var" inside your script like this: my($var); Then as soon as you are out of the code block you made it in, it no longer exists and gets destroyed. So if you want any of your variables easily located from other packages or namespaces you create in your modules, you have to create them in a different way, other than with my(), or simply by writing them out. You do this by simply typing their full address in Perl-speak: $main::foo = 'bar'; And then you can find them anywhere else by using the same address to locate them again. Pretty smooth, huh? Keep in mind that it's usually a better idea to use as many package variables as you need. That's because you can end up with scoping problems, or naming conficts within your script that you otherwise wouldn't expect. Plus, you'll also gobble up the memory allocated to your script much more quickly, because these variables never are destroyed until your script exits. [Q] Ok. So now that I understand the concept of namespaces, or 'packages' as we call them in Perl, let's talk about my first question again. Does the fact that I use() a module in my script, or call for a subroutine or variable inside that module automatically make my script an object oriented program? [A] Well, just like you first guessed, it does not. Think back to the last tutorial we shared when I explained how when you use() a module that Perl goes and gets it, then compiles it into a big ball of Perl byte code, and it is called a "class". And that's what you get right after you use() a module -- you get Perl to make you an object class, not an object. You see, an object class as we call them in OO, is just the template which Perl is going to use to make all the objects we want from it. Each time we ask Perl to make us an object of that class, we get a new and unique instance of it which has its own attributes and information inside. The method names don't change, but the data we pass to them, and specifically the arguments we specify for constructor method (which influences the behavior of other methods inside the script), do change. When you call an object method, you use OO syntax: # get Perl to make you a class # from the namespace called my_module use my_module; my($object_reference) = my_module->new( [arguments for this object that Perl will use to make it and customize it for you based on your needs] ); # call one of the object's methods $object_reference->object_method( [arguments for this routine] ); Otherwise you use regular syntax to call a subroutine in the raw class which Perl made for you when you used() it by name: $CGI::param('username'); [Q] But why can I just type this code here, and get to the param() subroutine in my CGI class without ever using a fully qualified Perl address to it, or by creating an object and calling it as a method via some kind of reference? use CGI qw(param); my($data) = param('data'); [A] Glad you asked. The reason is because some folks make their modules do a rather nasty thing commonly called 'exporting'. For those who don't care about the details of understanding OO programming, it is much more easy for then to think that they are importing everything in the CGI package to their script. When you do call a module like CGI.pm without it's proper OO syntax, it will 'export' some or all of it's innards into your main namespace. [Q] So why do you say that 'exporting' is a nasty thing? I think it's kind of convenient to not type a fully qualified Perl address to the subroutines in the CGI class by just having CGI.pm dump all its stuff into my script's package, or package 'main'. [A] Heh, heh, heh. My friend, you may think it convenient now to go about your usage of modules in such a way, but it is a practice very prone to cause you grief and pain later on. You see, as your scripts and personal code libraries grow in size, number, and complexity, you will quickly find that it causes what we call 'naming conflicts'. For example, what if you want to make a subroutine called 'param()' in your script? Uh oh, by doing so you just overloaded, or overwrote the subroutine you had CGI.pm export into your main package. S*$#!, doesn't that suck! The next time you call for param() to grab something for you out of an html form, you'll be calling your own subroutine instead. Quick, fast, and in-a-hurry you'll learn that it's just another head-ache you don't want to try keeping track of all the time when you just have too much code to risk it. Trying to find such bugs can often mean hours of nail-biting and hair-pulling until you discover your ingenious move :o) That's just one example in many. Not only can classes not called as OO objects export their subroutines, but variables too along with a bunch of other stuff you usually won't know about unless you dig through the source in all of your third-party modules. Call your modules directly with the arrow syntax... CGI->new(); ...instead of indirectly or only as classes. Even though you can call modules 'indirectly' to create objects... new CGI; ...it's often not such a good idea, for the same reason it's not a good idea to let modules just export all their guts into your main package or namespace. ALLRIGHTYTHEN! Here we must end our discussion, because I think that is all I'll be able write down tonight. Yeah, it's working on 1:30 now and I need to get some Zzzzz's before work tommorow. Comming up in the next OO tutorial(s)! [Q] If I'm going to sell out to this module approach, I am assuming I've got to actually make modules, rather than just using my old fashioned scripts (*.pl) as code libraries. What should I do? Do I just change my perl scripts from a .pl extension to a .pm? [Q] To "use" a module in my main script, show me again how to make new objects from its class, and how to get a reference to them. Show me how to do it with a module I make on my own. [Q] I think I've got the idea about putting all my code in the module. But what do I have to do to set it up so that the module grabs the information passed to its constructor method? [Q] Can you nest modules? I want to make a module that wraps around DBI and DBI:DBD. Can I do this?