POO Coding Tutorial 1:

Basics of Creating Functions

All coding in POO requires adding functions (or "methods", if you prefer) to objects. A function is a bit of Python code which can accept some parameters, perform operations (e.g., generating output, changing property values, etc.), and return zero or more values. Functions may be invoked via commands typed by the user, or called from other functions.

This tutorial assumes you've already been through the Builder's Guide, and you know how to create objects and set their properties. You should also keep the Programmer's Reference handy, though it's not necessary to read it in detail at this stage. It is suggested that you log into a POO server (or run a local copy) and follow along with the examples given below.


1. Immediate-mode commands

The simplest way to execute Python code within POO is to do it in immediate mode. Simply start your input with ";" or "%", followed by the code to execute, as illustrated in the example to the right.

(In the examples in these tutorials, what you type is shown in black, and POO's response is shown in green.)

The "print" command generates output to the user who typed the command; no one else in the room will see it. In the "s = 'spam'" example, you're assigning a value to a variable in your own temporary namespace; no one else will have access to this variable, and its value will be lost when you log out. The final line (";me.age = 42"), however, assigns the value 42 to the property "age" on your character object. This is equivalent to the POO command "@set me.age = 42".

poo>;print "foo"
foo
poo>;print 6*7
42
poo>;s = "spam "
poo>;print s*3
spam spam spam
poo>;me.age = 42
poo>

A common mistake is to omit the initial ";" or "%" when trying to execute immediate-mode Python commands within POO. Since the POO parser is unlikely to grok the raw Python code, you'll receive an error such as "Huh? (Verb "print" not found.)"


2. Test Functions

If you need to execute more than a single line of code, you'll need to write a function. It's often handy to reserve a property or two on yourself for temporary code and values; in this example, we'll use "test" for this purpose.

This example creates a method called "test" on your character object. This function is declared with two parameters. The first is "self", and is a special type of parameter: it must always be explicitly declared, but you almost never pass it explicitly; instead, it is automatically filled in with a reference to the object on which it was invoked. (If this is confusing, hang in there -- it may become clear with more examples.) The second parameter declared in this example is called "val", and is an ordinary parameter.

poo>@newfunc me.test(self,val)
Enter function code below:
[POO Editor -- enter .? for help]
edit>if val%2 == 0:
edit>    print val, "is an even number."
edit>else:
edit>    print "That's a pretty odd number."
edit>.l
---- Current Buffer ----
if val%2 == 0:
    print val, "is an even number."
else:
    print "That's a pretty odd number."
------------------------
edit>.x
Saved.
poo>;me.test(42)
42 is an even number.
poo>;me.test(43)
That's a pretty odd number.
poo>;me.test("spam")
TypeError in line 1 of <test> : not all arguments converted
poo>

This function assumes the parameter is a number, and prints a message that depends on whether the number is even or odd (using the "mod" operator, "%", which returns the remainder after division). Test the function by using an immediate-mode Python command, as shown. We've neglected to do any type checking, so if we call the function with a string, an error message is printed. Note that the message specifies what type of error occurred, as well as the function name and line number.


3. Inheritance and super()

In this example, we're going to override the standard description function so that an extra, randomly chosen message is appended to your normal description. First, use @edit to create a list of extra messages in an "extradesc" property, as shown. Each message must be a one-liner, since we're going to simply choose one line and append it to the description.

When a player looks at an object, that object's description method is called with the parameters "self" (i.e. that object) and "looker" (i.e., the player looking at it). We need to override the standard description function with our own, so we use @newfunc with the same name and parameters. (The exact name of the parameters is not significant, but they must match in number and meaning.) This function first chooses a random number between zero and the length of the "extradesc" property (i.e., the number of lines in that list). Then we want to append the chosen line to the usual description.

poo>@edit me.extradesc
[POO Editor -- enter .? for help]
edit>He sees you watching, and flashes a grin.
edit>You notice a can of spam in his pocket.
edit>A passing swallow barely misses his head.
edit>.x
Saved.
poo>@newfunc me.description(self,looker)
Enter function code below:
[POO Editor -- enter .? for help]
edit>r = randint(0,len(self.extradesc))
edit>return super(looker)+" "+self.extradesc[r]
edit>.x
Saved.
poo>look me
You see nothing special. You notice a can of
spam in his pocket.
poo>look me
You see nothing special. A passing swallow barely
misses his head.
poo>

To accomplish that, we want to call the "normal" description function from within our own. There is a special keyword in POO code for accomplishing that: super. The word "super" always refers to a function with the same name as the one you're in, but defined on some ancestor of the current object. By calling "super" with the same parameters (except "self", which is always implicit), you invoke the function that would have been invoked if you hadn't overridden it in the first place.

In this example, we get the value of the standard description by calling "super(looker)", and then adding the randomly chosen line from "extradesc". Now, each time someone looks at you, they will see a random bit of extra description appended to your normal description.

This is a simple example, but the implications are powerful. Object-oriented programming (OOP) lets you override or extend specific parts of the functionality inherited from ancestor objects, with minimal recoding. If you're new to OOP, it takes a little getting used to, but once it "clicks" you'll find it a very elegant approach to building complex objects.


4. Creating commands and show()

In this final example, we'll create a simple POO command which you can use to annoy your friends. This example also illustrates the show() command, a very important and powerful function for generating output.

All POO commands invoke functions, so first we must create a function -- "bonk" in this example. The bonk function takes one parameter in addition to "self"; this is a reference to the person (or other object) you're bonking. The code itself is a one-liner: a simple reference to show(). But what's all that gibberish in the parameter to show()?

poo>@newfunc me.bonk(self,whom)
Enter function code below:
[POO Editor -- enter .? for help]
edit>show( "%1I %1:(bonks) %2i on the head.",
edit>    {1:user, 2:whom} )
edit>.x
Saved.
poo>@cmd me.bonk <obj> calls bonk(%1)
bonk command defined on #2
poo>bonk Monty
You bonk Monty on the head.
poo>

The first parameter to show() is a string defining a message. But in place of most of the nouns, the message contains placeholders which start with "%". "%1I" means "an indefinite reference to object 1, capitalized." Here "indefinite" means that non-proper names will be prefixed with "a" or "an" rather than "the"; if the object has a proper name (e.g., "Sally"), then no article is used. Similarly, "%2i" is an indefinite reference to object 2, but not capitalized (but again, proper names are simply printed as they are). The verb is defined as "%1:(bonks)". This means that the verb "bonks" should be conjugated to match object 1; if that object is plural, the verb will be changed to "bonk". (For more info on show(), see the file msg.py, or ask me.)

The second parameter to show() defines what the objects actually are. Here, we're using "user" as object 1, and "whom" as object 2. "whom" is a parameter passed into the function. "user" is a built-in POO keyword, that always refers to the player who invoked the command. (For more bulit-in POO keywords, please see the "pooref.html">reference manual.)

The net effect of using show() is that three different messages are generated. If you name is "Sally", then Monty will see the message "Sally bonks you on the head," while you see "You bonk Monty on the head," and everyone else in the room sees "Sally bonks Monty on the head." The show() function is an elegant way to produce high-quality output, and it will be worth you time to learn it well.


http://www.strout.net/python/poo/tutorial1.html
Last Updated: 11/09/97 . . . . . . Joe Strout