Helpers
SenseTalk objects do not need to stand on their own. They can be helped by other objects that supply some or all of their behavior. For example, if you create a person object which has a handler to calculate the person’s age based on their birth date, that person object could be used as a helper for other objects, enabling them to also perform the age calculation without needing their own handler for that purpose.
Here is a sample script for an object which is helped by two other objects, named Rex and Sue:
sayHello -- let's start out by being friendly!
properties
helpers: [Rex, Sue],
birthdate: "May 14, 1942",
end properties
on sayHello
put "Greetings! My age is " & calculateAge()
end sayHello
This object’s sayHello
handler calls a function named calculateAge
. When the sayHello
handler is called, it will call calculateAge()
. This object doesn’t have a calculateAge function handler, but if one of its helpers, say Rex, does have such a function handler, that handler will be run on behalf of this object, to calculate the age.
Who is Me? What is This Object?
An object and its helpers work closely together, acting very much like a single object (think of the Three Musketeers’ slogan, "All for one, one for all"). When a handler in a helper is being run, it is treated as though it were a handler of the original object. In this context, me
and my
refer to the object being helped rather than the helper.
This means that any statements executed in the helper’s script will target their messages to the object being helped (and only indirectly, then, to the helper). It also means that if the helper uses me
or my
to access properties, it will be accessing the properties of the helped object. For cases where a script may need to target itself or access its own properties, the term this object
may be used instead of me
.
Helpers’ Place in the Message Path
An object’s helpers are also closely tied to it in the message path. When an object receives a message that it doesn’t have a handler for (or which it handles and then passes along), that message will go next to the object’s helpers. Only if none of the helpers handle the message will it be passed along to other objects in the message path, such as to those in the backScripts
.
Objects Designed to be Helpers
Any object can be a helper to one or more other objects. Suppose, for example, you have an object called Rex that has a calculateAge()
function handler. Then suppose you have another object, Luna, that needs the same calculateAge()
functionality. By adding Rex to Luna’s list of helpers, Luna gains that capability. But Rex may have other handlers as well, which may not all be desirable to include as part of Luna’s behaviors. How can you provide just the functionality that Luna needs?
One good way to deal with this situation is to separate out those behaviors (handlers) that may be useful to several different objects, and create a new object designed specifically to serve as a helper. For example, you might move the calculateAge()
handler out of Rex into a Person object, and then add Person to both Rex and Luna’s helper lists. Each object can have any number of helpers, so separating related groups of behaviors out into helper objects can be a very powerful tool, allowing you to re-use that functionality in various combinations in different objects.
Designing an Object to be a Helper
Many helper objects are quite simple, having nothing more than a script with a few handlers. A Person object, for example, might start off with just a single handler, like the calculateAge()
function that we’ve been talking about:
to calculateAge -- returns my current age in years
return (the date - my birthDate) / 365.25 days
end calculateAge
More on Me (oh My!)
One very important thing to understand about helpers is that when the terms me
and my
are used in the script of a helper, they refer to the object being helped and its properties, not to the helper or its properties (use this object
if necessary to refer to the helper). This usually means that a handler written as part of an object will also perform correctly when helping another object, without any changes.
Making Objects Based on Other Objects
Simply using one object as a helper to another in order to borrow the first object’s behavior is very easy, often requiring no special effort on your part. Once you’ve decided to separate some of the functionality of your scripts into an object that will serve mainly as a helper to other objects, there are some additional capabilities you may want to take advantage of.
Earlier in this section, we saw how a simple object could be created using a new object
expression. It was mentioned that the more common way to use a new object
expression is to indicate a particular type of object that you want to create by providing the object it should be based on, as shown in this example:
put new Person with {name:"Elizabeth", age:14} into daughter
Here, Person is the name of an object (known as a "prototype" object) being used to define the newly-created object. In this example SenseTalk will look for an object named "Person" and send that object a makeNewObject
function message with the initial properties supplied as a parameter. This gives the prototype object the chance to control exactly what the new object will be like. Typically, the new object will be based on the prototype object itself, by having the prototype object as its helper, thus inheriting all of its behaviors, and by receiving a copy of the prototype's regular properties (other than its script and helpers). Let’s look more closely at exactly how this works.