Siaris
Simple Things
Syndicate: full/short
Siaris
Categories
General0
News2
Programming2
LanguageBits0
Perl50
Ruby10
VersionControl1
Misc1
Article Calendar
<= July, 2008
S M T W T F S
12345
6789101112
13141516171819
20212223242526
2728293031
Search this blog

Key links
External Blogs
Brought to you by ...
Ruby
1and1.com

Adding Accessor Methods (soot part IV)

Andrew L. Johnson (First published by ItWorld.com 2001-06-21)

Last week we started our Slot module and defined a constructor. We tested it my creating a new object and accessing its ‘credits’ key, which we said was a Bad Thing(tm). Let’s add an object routine to our module that returns the current value of the ‘credits’ attribute (this is called an accessor method):

    sub credits {
        my $self = shift;
        return $self->{credits};
    }

It is OK to access the datastructure directly inside the object module, it is the outside world that should get its information from object methods. This method shifts off the first argument, which will be the object itself (a reference to the hash) and returns the value of the ‘credits’ key in that hash. That’s it. We can now modify the little test script from last week to use this method rather than accessing the value directly:

    #!/usr/bin/perl -w
    use strict;
    use Slot;
    my $slot = Slot->new(100);
    print $slot->credits(),"\n";

Why is this better than directly accessing the hash key itself? Because, as a user of this module, we aren’t supposed to know (or care) that the object is a hash. It could have been an array reference, or it could be in the next release. If we wrote code that accessed the object as a hash, and then we downloaded the latest version and the author changed it to use an array reference underneath, all our current code would break. Just to show you, let’s rebuild the module using an array:

    package Slot;
    use strict;

    sub new {
        my $class   = shift;
        my $credits = shift || 100;
        my $self    = [ $credits, # credits
                        1,        # bet
                        0,        # win
                        0,        # paid
                        undef,    # spin
                       ];
        return bless $self, $class;
    }

    sub credits {
        my $self = shift;
        return $self->[0];
    }

    1;
    __END__

Maybe the module author decided that array accesses are faster (not enough to warrant using them in this case for sure, but it’s an example), and changed the module to this version. Our new code that uses the credits() method still works just fine, but our old code that used $slot->{credits} won’t work at all now.

And that’s a very important point about objects — the object encapsulates the data and provides an interface for us to use. Just like we don’t need to know how a real slot machine (or radio) works inside, we shouldn’t need to know how our object is built on the inside (unless we are the ones building it of course). That means, as an object builder, you need to provide any methods the user might need to operate the object. This means you will be free in the future to change the underlying object and the user never needs to know and doesn’t have to worry about a new version breaking old programs that use it.

Let’s quickly add another attribute method, the bet() method:

    sub bet {
        my $self     = shift;
        $self->{bet} = shift || $self->{bet};
    }

This is a dual purpose method — we not only have a way to retrieve the current betting amount, we can also set it at the same time. This is a useful way of creating accessor methods instead of creating separate get_bet() and set_bet() methods. If an argument is passed to this method and it is not 0, we set the bet attribute to the new value and return it, otherwise we use the old value. We haven’t done any error checking to ensure an integer was passed in, that is an exercise for the reader.

We haven’t yet actually defined how our slot machine will work, and that will be the subject of next week’s discussion.

*****

The Constructor (soot part III)

Andrew L. Johnson (First published by ItWorld.com 2001-06-14)

The basic framework of an OO module is simpler than a standard module because OO modules don’t export anything.

    package Slot.pm
    use strict;

    # any class data

    # class and object methods (subroutines) here

    1;
    __END__

Like a normal module you provide a package name and end with a true value. In between you define whatever class data (if any) you need, and write the subroutines that create an instance of the object (the ‘constructor’) or provide methods that the object can perform.

The only real difference between an object or class method and an ordinary subroutine is that perl does a little magic relating to the first argument the subroutine gets. Recall how methods (class or object) are called:

    my $obj = MyClass->new('argument');   # constructor: class method
    $obj->some_method('argument');        # object or instance method

You may also see methods called using the indirect object syntax:

    my $obj = new MyClass 'argument';

Most people avoid this calling form except for a class method such as the constructor. Either way, you need to know that first argument to the routine is the object itself (for an object method), or the class name (for a class method such as the constructor).

Typically the constructor is named new(), but that is only a convention. We wanted our constructor to be called with an optional argument defining how many credits to start with:

    my $slot = Slot->new(100);

So, our constructor will begin like:

    sub new {
        my $class   = shift;         # class name is first argument
        my $credits = shift || 100;
        # ... more stuff
    }

Now we have enough information to start construction of our object, but what is an object? An object is simply a reference to anything that you can take a reference to, and that reference is "blessed" into the class (we will get to that shortly). Quite often a hash reference is used because it provides a convenient way to have named attributes or properties in the object (attributes are the actual data the object stores). Our Slot object will need a few attributes: the number of credits remaining on the machine, the current betting amount, the spin result (what is displayed), and information regarding whether it was a winning spin and how much was paid. Our Slot module and constructor now look like:

    package Slot;
    use strict;

    sub new {
        my $class   = shift;
        my $credits = shift || 100;
        my $self    = { credits => $credits,
                        bet     => 1,
                        win     => 0,
                        paid    => 0,
                        spin    => undef,
                       };
        return bless $self, $class;
    }

    1;
    __END__

That’s it — we now have an OO module that creates an instance of a slot machine. It doesn’t do anything now because we haven’t created methods for it, but you can actually test this module:

    #!/usr/bin/perl -w
    use strict;
    use Slot;
    my $slot = Slot->new(100);
    print $slot->{credits},"\n";

Note, the $slot variable is really just a reference to a hash, and we have used it as an ordinary reference to access the ‘credits’ key. This is a Bad Thing(tm), and I only show it to you to demonstrate that the object is simply the hash reference we got back from the new() method. However, it isn’t really just a hash now, it has been "blessed". The bless() function is a perl built-in that associates a reference with a class — this is what will allow perl to find a given objects methods (remember, we didn’t import anything). Our Slot class doesn’t define any object methods yet, and that is the topic for next week’s discussion.

*****

Envisioning the object (soot part II)

Andrew L. Johnson (First published by ItWorld.com 2001-06-07)

Last week we looked some basic concepts of objects and how to use an object in a program. This week we’ll begin building an object oriented module (a class) from scratch. Rather than create some abstract data structure from a computer science course, we’ll build something to simulate a real world object: a slot machine.

Before we build our slot machine we need to ask ourselves a few questions about how we interact with such a machine (hypothetically speaking of course). A slot machine has a pretty simple interface: in a nutshell, you put money in and you pull the lever, and sometimes you even get some money back out. Modern machines haven’t changed the interface much — now you can put some quantity of money in (giving you credits) and then bet various (usually small) amounts. This allows you to put all your money in at once and then lose it without having to keep putting coins in with every pull. That’s the basic idea we will use with our slot machine.

So, if we want to write a program that uses our slot machine we will want to be able to do the following things: 1) Initialize the slot machine with some amount of credits; 2) Be able to find out how many credits we have left; 3) Be able to determine our current bet, and change our current bet; 4) Pull the lever to spin the "wheels". We will probably also want to be able to display a pay-out table so that players know what results they should wish for.

Let’s first build a small interactive test program to play a slot game using our imaginary object with 100 credits to start with:

    #!/usr/bin/perl -w
    use strict;
    use Slot;
    my $slot = Slot->new(100);
    while(1){
        my $credits  = $slot->credits();
        my $curr_bet = $slot->bet();
        last if $credits < 1;

        print "You have $credits credits remaining: max bet is 3\n";
        print "Enter your bet ('q' to quit) [$curr_bet]: ";

        chomp(my $bet = <STDIN>);
        last if $bet eq 'q';
        $bet ||= $curr_bet;

        $slot->spin($bet);
        print $slot->results();
    }

    print "Game Over\n";
    print "You have ", $slot->credits(), " remaining\n";
    print "Thank you for playing\n";
    __END__

Obviously we can’t run this program until we build our slot object, but now we not only have a description of the interface to our object, but a test program as well. To begin with we load our Slot.pm module and then create a new Slot object via the Slot->(100) class method (we imagine passing in the number of credits to play with, in this case 100). Then we start an infinite loop (well, infinite only if we are incredibly lucky and keep winning more than we lose). In the loop we grab the current credits remaining and the current betting value (default will be one credit). If we have less than 1 credit, the game is over.

The next little snippet merely informs the user of how many credits they have, the maximum bet, and prompts them to enter a bet. We grab the bet (if any) and exit the loop if it is ‘q’, we then set the bet to the current betting amount if they entered nothing (we aren’t bothering with validating user input at this point). We then spin() the slots using the slot() method and print the results of the spin with the results() method. If we exit the loop we display a message informing the user of their winnings (if any) and the game is over.

That sums up the interface to our slot machine object. In the next few installments we will begin building the slot machine itself.

*****

Simple Object Oriented Tutorial (soot part I)

Andrew L. Johnson (First published by ItWorld.com 2001-05-31)

Object Oriented Programming (OOP) means a lot of different things to a lot of different people — but for our purposes let’s just say that OOP is simply a way to create a "thing" that your programs can use (obviously, this is rather vague at the moment).

Before we delve into making a simple object, let’s look at using an object and explore a few concepts. Consider a radio, the kind your grandfather might have had — a large wooden box with a speaker, a volume dial, and a tuning dial with the frequencies shown. We do not necessarily need to know what the insides look like, or how it functions, we need only know how to operate this device (we need to know how to use the device’s interface). Radio’s have changed a great deal since those days — instead of tubes inside we have solid-state circuits — and they are generally much smaller. But the interface has hardly changed at all: We still have a speaker, and volume and tuning controls (though we may have a digital display of the radio frequencies, and the controls may operate by mere touch rather than actually turning a dial). Everything on the inside has changed, but the only difficulty grand-dad might have using it is finding a station that played something he could stand to listen to. We will return to this radio analogy as we progress.

Now let’s look at using an existing object oriented module in Perl. The LWP modules provide us with easy methods of fetching web pages from the Internet (the modules are available in the libwww package on CPAN). The following is a very simple script to fetch a web page, based on an example in the lwpcook.pod documentation that comes with the module set:

    #!/usr/bin/perl -w
    use strict;
    use LWP::UserAgent;

    my $ua = LWP::UserAgent->new();
    $ua->agent("TestBot/0.1"); # pretend we are very capable browser

    my $req = HTTP::Request->new('GET' => 'http://www.perl.com/');
    $req->header('Accept' => 'text/html');

    # send request
    my $res = $ua->request($req);

    # check the outcome
    if ($res->is_success) {
       print $res->content;
    } else {
       print "Error: " . $res->status_line . "\n";
    }

To fetch a web page, we have to open a socket and communicate with a web server on a particular port number and request the page using the HTTP protocol. But conspicuously missing from the above program is anything resembling socket handling or communication with a web-server. Instead we created two objects, told those objects what we wanted, and they handled all the messy details. All we needed to know was how to use the objects themselves — just like I do not need to know how my radio actually tunes in radio stations and plays music seemingly out of thin air, I only need to know how to operate the controls.

We first pulled in the LWP::UserAgent module (this provides with the "agent" that does the talking to a web-server), which also pulls in the HTTP::Request module. We obtained a new UserAgent object by calling the new() method of the LWP::UserAgent class.

Brief working definitions: A class is something that defines objects and their methods; a method is simply a subroutine that is connected to a class or objects defined by a class. We will get to these in a later segment of the tutorial.

The documentation tells us that we should give our agent a name using the agent() method (called as: $ua->agent("name/version")). Next we construct an HTTP request (what web page are we requesting), by creating a new() HTTP::Request object and telling what URL we want to GET. We also use the request object’s header() method to tell it we will Accept a text/html document.

Internally, these two objects "know" what to do when their methods are called, we only have to press the right buttons or turn the right dial. So, now that we have an agent and a request, we ask the agent to make the request() and assign the result to a new variable. This result is also an object (we did not create it, the request method gave it to us) that knows if it was successful or what error might have occurred. We need only test it for success, or print the error.

In the real world, we might have a radio tuned to a particular station, but that doesn’t help us hear a particular song — for that we’d need to make a request to the station (the radio won’t help us here). We may call the station on the phone, talk to the DJ to make our request, and he may tell if he’ll play the song and we can sit back and wait for it. If we had a box next to our radio that allowed us to type in a radio station and a song request and just hit a button, that would not be dissimilar to the above snippet to fetch a web-page. All the messy details of phone numbers and talking to the DJ would be hidden from us, and we’d simply have to know what buttons to push on our little ‘Radio::Song::Request’ black box.

This initial segment of our tutorial is only meant to give you a handle on the basic concept of an object. In subsequent installments we will begin building our own little black box.

Special Perl Variables

Andrew L. Johnson (First published by ItWorld.com 2001-05-24)

Last week we discussed the input record separator variable ($/), one of Perl’s special global variables. Perl has a large number of special variables (all listed and explained in the perlvar manpage), but you really only need to be familiar with a handful (or two) for most programming requirements. The following subset lists the most common such variables, the remainder can be looked up in perlvar as needed.

    $_      The default variable (often used, seldom seen)
    $/      Input record separator (default is "\n")
    $\      Output record separator (default is "")
    $,      Output field separator (default is "")
    $"      Field separator for interpolated arrays (default is " ")

    $|      Autoflush variable for currently selected filehandle
    $ARGV   Name of current file being read by <ARGV>
    $.      Current line number being read

    $0      The name of the current script
    $$      The current process id

    $1..$N  Captured data in regular expressions

A couple of things to be aware of: $ARGV provides the name of the current file being read via <ARGV> — and you should remember that whenever you do something like:

    while (<>) {
        print;
    }

The empty <> is either reading from STDIN, or ARGV (the latter if there were any arguments in the @ARGV array). When reading from ARGV, the $ARGV variable will be set to each filename in turn. Also, when reading from ARGV, the $. variable does not automatically reset between files, so it will represent the current total line number (see the documentation for the eof() function to work around this).

There are also some special array and hash variables you need to know:

    @ARGV   The command line argument array
    @_      The subroutine argument array

    %ENV    Hash of environment variables
    %INC    Hash of filenames that have been included (via do(),
            require() or use).
    @INC    Search paths to find included files

    @EXPORT     List of things to export from a module by default
    @EXPORT_OK  List of things to export from a module on demand
    @ISA        Inheritance

The latter ones listed above are only relevant for creating modules, and you shouldn’t need them for general programming. The @INC array lets Perl know where to look modules or libraries that you include via ‘use’, do(), or require(). By default it holds all the necessary paths created when perl itself was built and installed (which is where most new modules will be installed as well). Sometimes you need to install modules in non-standard places and you will need to be able get these paths into the @INC array so perl can find them.

There are a couple of ways you can modify the @INC array. The first is to use the PERL5LIB environment variable — if that is defined when you start your script, then the paths defined will be prepended to the @INC array. To add paths to this array within your script, you can use the ‘use lib’ pragma:

    #!/usr/bin/perl -w
    use strict;
    use lib qw(/home/jandrew/perl/lib);
    use MyModule;
    ...

The above first prepends the path ’/home/jandrew/perl/lib’ to the @INC array, then the call to ‘use MyModule’ will search that path first to try to locate the module in question.

*****