Coding Domain

Perl Programming


Why using Object Orientated Programming?
This article explains the basics of Object Orientated Programming (OOP), in context with Perl. Most of the time, you don't want to work with objects in Perl. You can make nice programs without it, right?

Because I only write large programs in Perl when working with the CGI capabilities of the language, I'll use examples from those situations. I simply haven't seen any large non-CGI programs written in Perl.

Large software basics
I'll assume you are familiar with this, but it's important that you realize this. Here are some basic notes about large programs.

Getting problems without OOP
I'll say it again: Most of the time, you don't want to work with objects in Perl. You can make nice programs without it, right?

But, is your program really nice without the OOP?

Let me give you some examples. These examples just illustrate a problem. later, I'll explain how to solve them with OOP.

Example1: A user account system
Most large CGI programs have an user registration and login system, with some very nice and interesting functions for members. Large CGI programs mostly provide a control center for Administrators, and that requires cookie management, a login dialog and password storage and encryption.

However, what will you do when your site is getting larger and larger, and finally you end of with 4 large CGI programs? Do users have to register themselves 4 times, for every program once? Even worse - they have to login 4 times when they want to use many things at your web site.

But now, let's look at the problem from the site of the programmer. Will you really program such a registration system for every program, or copy-parse some parts, and adjust everything a bit? Eventually, you'll find a huge bug. Just overwriting the files won't do much good. Every file has some minor differences, as we just mentioned. You'll have to make all changes 4 times, and eventually, you get sick of it and stop your activities.

Wouldn't it be a lot easier if you created one system that could be used from different programs?
Your script can load a module that exports some subroutines, and implement some variables and settings because the module is very flexible in use. In other words, you're stuck with even more subroutines and variables. In the end, you'll loose the overview. Other programmers will never be able to understand where some things happen in your program. There are simply too many lousy subroutines involved, and nobody wants to document everything, isn't it? I refuse to do that part as well sometimes.

Example2: My current situation
I've just finished version 1.05 of the X-Forum Discussion script. It's a nice robust program, it's code is pretty structured. Most of the rules for large programs are applied. Well, that's wrong with it, you might say... Or do you really think that program isn't that large? Then, download it, and take a look at the code. I hope you can keep overview of all the code. I know where everything is located and what it does, because I've created it.

Still, nothing really seams to be wrong, but have you seen the initializations? About 50 global variables are declared, used through the entire program. Some modules are loaded, which functionality will be used throughout a lot of components of the program. The settings, language files will be loaded. Finally some basic initializations are made, concerning loading of more files, and test for banned members, missing files, etc...

For my download manager is build the same way; pretty robust, but not flexible.

But what if I want to:

In all situations, the other script has to implement all the variables, subroutines, required files, and language pack support first. After that, you can call that singe subroutine you wished to use in that other program. Meanwhile, there is a big change that one of those initializations of the forum or download manager does something you don't want to happen.

The solution through OOP
Wouldn't it be great that our program only has to load one module, and tells it that what kind of information it needs. The module should be intelligent enough to handle this. The module should be completely independent, and know what to do. This should result in the following requirements for the modules:

Objects
OOP eliminates the need to declare enormous data structures. We work with objects instead. Objects are key to understanding object-orientated technology. This is very much alike a real life situation.

For example, we have a television set (the object).

Doing the same thing in Perl
There is an online tutorial for that. Here we explain in pseudo-code what we can do.

main program

variable (TV) tv1 = new TV(500,400)
variable (TV) tv2 = new TV(400,300)

tv1->attachConnection(cable1)
tv2->attachConnection(cable2)

tv1->turnOn()
tv2->turnOn()

tv1->changeChannel(2)
wait 5 minutes
tv1->turnOff()

tv2->changeChannel(3)
wait 5 minutes
tv2->turnOff()

This creates two TV's from scratch. Both TV's work independent from each other. Through the methods we can let the TV do something. We don't know how it works, but we can handle it. You also don't get confused with tons of subroutines. All actions are embedded within the object, and only accessible when you know of the object itself.

Definition of a TV

class TV {

  # The hidden object variables define the properties of an object
  variable (number) channel
  variable (Connection) connection
  variable (Screen) screen
  variable (number) hertz

  # A constructor that initializes the object on creation
  subroutine constructor(number width, number height) {
    self->channel = 1
    self->screen = new Screen(width, height);
  }

  # Turn on
  public method turnOn() {
    call showImage every 1/30 of a second
  }

  # Display an image at the screen
  private method showImage() {
    image = screen->retreiveImage(hertz)
    screen->display(image)
  }

  public method turnOff() {
    stop calling timer_action
  }


  # Switch channel
  public method changeChannel(number newChannel) {
    self->channel = newChannel
    self->hertz = connection->getChannelFrequency(self->channel)
  }


  # Handling a connection, The connection variable can also 
  # be changed from outside, through this method
  public method attachConnection(Connection newCable) {
    self->connection = newCable
  }

  public method disconnect() {
    self->connection = undefined
  }

  # Some methods to return the internal data, read-only
  # because we don't provide methods to change the data
  public method getWidth()   { return self->screen->width   }
  public method getHeight()  { return self->screen->height  }
  public method getChannel() { return self->channel }
}

This TV class is very simple, but shows how a class can look like. Take a look at the comments inserted in the code, and you'll properly understand what is done here. Very much is delegated to other objects, to simplify the example. However, we can create and work with a TV everywhere now, in every program, in any situation. Just like we wanted. The hidden variables inside the TV aren't shared among other TV's, which avoids the need to make collection structures.

Written by Diederik van der Boor at 10 March 2001