Alternate object oriented programming model

8 views
Skip to first unread message

Mike Rozak

unread,
Feb 11, 2004, 2:06:58 AM2/11/04
to
My (limited) understanding of TADs and Inform is that a programming object
generally corresponds to a virutal world object (door, key, person, etc.).
Each programming object has properties and methods associated with it.
Methods (and properties) are inhereted from multiple superclasses. IE: A
"sword" is both a "weapon" and a "metal object", inhereting properties and
methods from both.

Furthermore, the code for a verbs (such as "get" or "magnetize") is stored
within the object definition. "Get" would be inhereted from the master
"can-carry" superclass, and "magentize" would be inhereted from the "metal
object" superclass.

Another approach is to have a list of verbs and functions associated with
them. The verb-code calls into the object it's acting on to see if the
object provides an override. If it's not overriden then standard behavior is
used. Thus, there's one "Get" function that looks at an object's property
for "CanGet" or calls into the object for "BeforeGet" to see if can be
picked up, and "AfterGet" to display special strings.

I was looking throuh some articles in http://www.skotos.net/articles/ and
noticed a few by Richard Batle talking about a differnt way to approach
verb/object associations... the articles are
http://www.skotos.net/articles/dawnof01.shtml through
http://www.skotos.net/articles/dawnof08.shtml. (He also mentions this
technique in the "Designing virtual worlds" books.

Here's basically what he says: (It took me quite awhile to parse his
explanation, so I've rewritten this in my own words.)

The approach that I described above (when describing Inform/TADs) is
workable, but there is a potentially better system. As an example, he talks
about the verb "hit" and variations such as "slap", "kick", and "punch".
which sometimes do the same thing as hit, but not always.

Richard suggests that intead of attaching the code for an action to an
object (with a verb as a method), or to a function (for the verb), attach it
to the combination of verb and object... this creates an NxM matrix of code,
where N is the number of verbs and M is the number of objects.

Of course, this is too much code. To reduce the size, associate the objects
with one or more superclasses (like Inform/TADs) AND (here's the important
part) assocaite verbs with one or more superclasses. Thus, "slap", "kick",
and "punch" would be subclasses of "hit". Then, the table is an AxB matrix
(A = number of verb superclasses, B = number of object superclasses) of
code. (A << N, B << M)

To reduce the code futher, leave many of the code fields blank and
automatically back off to the next highest superclass. This ends up acting
like method inheretence in Inform/TADs; if a "metal object" doesn't know
anything about being picked up, the code from the "can-carry" class is used.

He then waves his hand and says that a clever and fast algorithm for backing
off to superclasses can be written.


The advantage of associating code with a tuple of verb and object follows:

Example: Assume that Slapping, kicking, and punching are subclasses of the
verb "to hit". Fred, Tom, and Mary are a subclasses of "person".

For the most general rule, associate "hit person" with code to make them
angry. Thus, if you hit fred, slap mary, or kick tom, the reactions are all
the same.

However, you can also make a more specific rule "slap fred" that causes him
to challenge you to a duel, while hitting, kicking, or punching him will
still make him angry.

Similarly, "kick mary" could evoke a different response than "slap marry".

Hitting, kicking, punching, or slapping Tom might all have the same effect,
requiring no extra code.


The approach can be generalized more to include triplets, like "put
can-carry-object container", which would allow the placement of any object
that can be carried into a container. This could be overruled by "put
magnetized-object metal-container" to ensure you can't put a magnetized
object into a metal container (perhaps it sticks to the side before you can
put it in). Because of the lack of backoff cases, you would be able to put a
magnetized object in a non-metal container, or a non-magnetized object in a
metal-container though.

It seems fairly comprehensive, but I'm not sure if it's worth the work from
the author's POV. (I was thinking of something vaguely similar many months
ago, but more from parser POV, where I can envisage a benefit.)


Does anyone have any experience with this approach? (Perhaps TADs and Inform
use it and I missed this in the documentation?)


--

Mike Rozak
http://www.mxac.com.au


matteo.desimone

unread,
Feb 11, 2004, 4:24:31 AM2/11/04
to
Mike Rozak wrote:

> Richard suggests that intead of attaching the code for an action to an
> object (with a verb as a method), or to a function (for the verb), attach it
> to the combination of verb and object... this creates an NxM matrix of code,
> where N is the number of verbs and M is the number of objects.

Well, I wrote some adventure usign a similar approch but using BASIC and
Lua laguages.
In Italy, in the '80th, a great book about Text Adveture by Enrico
Colombini, used similar approch: now I've some problem switch to the
Inform's model :)
The code is more simple usign this table driven model, IMHO.

Bye,
matteo!

Rexx Magnus

unread,
Feb 11, 2004, 4:40:45 AM2/11/04
to
On Wed, 11 Feb 2004 07:06:58 GMT, Mike Rozak scrawled:

>
> Furthermore, the code for a verbs (such as "get" or "magnetize") is
> stored within the object definition. "Get" would be inhereted from the
> master "can-carry" superclass, and "magentize" would be inhereted from
> the "metal object" superclass.
>
> Another approach is to have a list of verbs and functions associated
> with them. The verb-code calls into the object it's acting on to see if
> the object provides an override. If it's not overriden then standard
> behavior is used. Thus, there's one "Get" function that looks at an
> object's property for "CanGet" or calls into the object for "BeforeGet"
> to see if can be picked up, and "AfterGet" to display special strings.

*Snip*

Inform works like this anyway, from what I can tell.


> Example: Assume that Slapping, kicking, and punching are subclasses of
> the verb "to hit". Fred, Tom, and Mary are a subclasses of "person".
>
> For the most general rule, associate "hit person" with code to make them
> angry. Thus, if you hit fred, slap mary, or kick tom, the reactions are
> all the same.
>
> However, you can also make a more specific rule "slap fred" that causes
> him to challenge you to a duel, while hitting, kicking, or punching him
> will still make him angry.
>
> Similarly, "kick mary" could evoke a different response than "slap
> marry".
>
> Hitting, kicking, punching, or slapping Tom might all have the same
> effect, requiring no extra code.
>

The same with this, as it applies to this example, and the example above.

--
http://www.rexx.co.uk

To email me, visit the site.

Sam Denton

unread,
Feb 11, 2004, 7:47:19 AM2/11/04
to
"Mike Rozak" <Mike...@bigpond.com> wrote in message news:<mwkWb.51418$Wa.4...@news-server.bigpond.net.au>...

> My (limited) understanding of TADs and Inform is that a programming object
> generally corresponds to a virutal world object (door, key, person, etc.).
> Each programming object has properties and methods associated with it.
> Methods (and properties) are inhereted from multiple superclasses. IE: A
> "sword" is both a "weapon" and a "metal object", inhereting properties and
> methods from both.

True.

> Furthermore, the code for a verbs (such as "get" or "magnetize") is stored
> within the object definition. "Get" would be inhereted from the master
> "can-carry" superclass, and "magentize" would be inhereted from the "metal
> object" superclass.

TADS, maybe, not Inform.

> Another approach is to have a list of verbs and functions associated with
> them. The verb-code calls into the object it's acting on to see if the
> object provides an override. If it's not overriden then standard behavior is
> used. Thus, there's one "Get" function that looks at an object's property
> for "CanGet" or calls into the object for "BeforeGet" to see if can be
> picked up, and "AfterGet" to display special strings.

Inform's standard library works like this.

> I was looking throuh some articles in http://www.skotos.net/articles/ and
> noticed a few by Richard Batle talking about a differnt way to approach
> verb/object associations... the articles are
> http://www.skotos.net/articles/dawnof01.shtml through
> http://www.skotos.net/articles/dawnof08.shtml. (He also mentions this
> technique in the "Designing virtual worlds" books.

I'll read these later, for now I'll go by your paraphasing.

[explaination of techniques that suffer from combinatorial explosions,
and ways to get around it via superclasses]

> He then waves his hand and says that a clever and fast algorithm for backing
> off to superclasses can be written.

Generally true, although multiple inheritance slows things down a bit.

> The advantage of associating code with a tuple of verb and object follows:
>
> Example: Assume that Slapping, kicking, and punching are subclasses of the
> verb "to hit". Fred, Tom, and Mary are a subclasses of "person".
>
> For the most general rule, associate "hit person" with code to make them
> angry. Thus, if you hit fred, slap mary, or kick tom, the reactions are all
> the same.
>
> However, you can also make a more specific rule "slap fred" that causes him
> to challenge you to a duel, while hitting, kicking, or punching him will
> still make him angry.
>
> Similarly, "kick mary" could evoke a different response than "slap marry".
>
> Hitting, kicking, punching, or slapping Tom might all have the same effect,
> requiring no extra code.

Again, I can't speak for TADS, but this is fairly easy to do in
Inform. For example, the default Attack action covers most of the
verbs mentioned. An author can take some of the verbs, 'slap' and
'kick' for example, and pull them out of the Attack grammar and create
Slap and Kick actions, which would then be written to use the
AttackSub code in the default case. Fred, however, can specify a
"before:Slap" to intercept slaps, and Mary can do the same with
"before:kick". (Note: this is not the actual Inform syntax, but it
gets the point across.) Or, a KnightlyNPC class, of which Fred would
be a member, could specify a 'before:Slap' routine which would apply
to Fred and his comrades.

[more stuff about indirect objects]

Inform uses what are called 'fake actions' to handle indirect objects.
Quoting DM4, "Receive is sent to an object O when a player tries to
put something in O, or on O. In the rare event that O needs to react
differently to these two attempts, it may consult the library's
variable receive_action to find out whether ##PutOn or ##Insert is the
cause." So, the class of magnets can have a before:PutOn that checks
for ferrous indirect objects and diverts to a new fake action,
StickTo, while ferrous containers could have a before:Receive that
would check for magnets and divert to the same fake action.

I think that Inform (and probably TADS since I hear it's of roughly
equal power) is doing pretty much what is described, but the so-called
"syntactical sugar" isn't quite the same. Getting around the "MxN"
matrix is the trick, and using classification schemes is the way to do
it. Inform classifies objects into classes, and verbs into actions
via grammar. Inform's grammar lacks the full hierarchy of objects and
classes, but specialization of verbs is less frequently needed.

Speciallization basicly turns the full MxN matrix into a sparse
matrix, one with many null entries. Classically, this is done via
lists and the efficiency gains come from how one scans the lists to
find an entry. The method used by Inform's standard library is to
broadly classify verb-objects into their Action-classes and then to
stick the exceptions into the objects and classes via 'before:Action'
and 'after:Action' clauses. This seems to work pretty well in
practice, but there are kludges due to a desire for backwards
compatibility. Inform has a second library, called Platypus, that
tries to get around the problems with the standard model by
sacrificing the backwards compatibility. It isn't used as much,
perhaps because of a lack of documentation: no one has rewritten DM4
and IBG to use it instead.

Quintin Stone

unread,
Feb 11, 2004, 9:27:06 AM2/11/04
to
On 11 Feb 2004, Sam Denton wrote:

> Again, I can't speak for TADS, but this is fairly easy to do in Inform.
> For example, the default Attack action covers most of the verbs
> mentioned. An author can take some of the verbs, 'slap' and 'kick' for
> example, and pull them out of the Attack grammar and create Slap and
> Kick actions, which would then be written to use the AttackSub code in
> the default case. Fred, however, can specify a "before:Slap" to
> intercept slaps, and Mary can do the same with "before:kick".

In TADS, the "attack" verb has the synonyms of "kill" and "hit". As is,
this means that all three actions have the same results. If I want, I can
add the synonyms for "slap" and "kick" and they would also be
indistinguishable. However, I can create separate verbs for kicking and
slapping (kickVerb and slapVerb) that, by default for all objects, refer
to the verify and action methods of the standard attack verb. Those two
verbs now do the exact same thing as the general "attack". To customize
the response to these two verbs for any specific object, I merely override
them in that object's definition. Therefore, Fred would have his own
custom doSlap(actor) method and Mary would have her own doKick(actor)
method.

Instead of some vague matrix, though, all this information is simply
recorded as part of the object definitions (as, I think, they should be).

/====================================================================\
|| Quintin Stone O- > "You speak of necessary evil? One ||
|| Code Monkey < of those necessities is that if ||
|| Rebel Programmers Society > innocents must suffer, the guilty must ||
|| st...@rps.net < suffer more." -- Mackenzie Calhoun ||
|| http://www.rps.net/QS/ > "Once Burned" by Peter David ||
\====================================================================/

Andrew Plotkin

unread,
Feb 11, 2004, 12:54:03 PM2/11/04
to
Here, Mike Rozak <Mike...@bigpond.com> wrote:
>
> The approach that I described above (when describing Inform/TADs) is
> workable, but there is a potentially better system. As an example, he talks
> about the verb "hit" and variations such as "slap", "kick", and "punch".
> which sometimes do the same thing as hit, but not always.
>
> Richard suggests that intead of attaching the code for an action to an
> object (with a verb as a method), or to a function (for the verb), attach it
> to the combination of verb and object... this creates an NxM matrix of code,
> where N is the number of verbs and M is the number of objects.
>
> Of course, this is too much code. To reduce the size, associate the objects
> with one or more superclasses (like Inform/TADs) AND (here's the important
> part) assocaite verbs with one or more superclasses. Thus, "slap", "kick",
> and "punch" would be subclasses of "hit". Then, the table is an AxB matrix
> (A = number of verb superclasses, B = number of object superclasses) of
> code. (A << N, B << M)

I've had thoughts along these lines. What I really want to do is
organize the outcomes in a tree, instead of a matrix. It would boil
down to a sequence of branches ("Is the verb GET?" "Is the object
heavy?" "Does the object jingle when moved?").

The fun part is coming up with an organizational scheme which lets the
author customize the tree without having to remember the entire
structure at once. I don't have that figured out yet. When I do,
writing a compiler will be the easy part. :)

--Z

"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*
* Make your vote count. Get your vote counted.

OKB (not okblacke)

unread,
Feb 11, 2004, 1:57:55 PM2/11/04
to
Mike Rozak wrote:

> To reduce the size, associate the objects
> with one or more superclasses (like Inform/TADs) AND (here's the
> important part) assocaite verbs with one or more superclasses.
> Thus, "slap", "kick", and "punch" would be subclasses of "hit".
> Then, the table is an AxB matrix (A = number of verb superclasses,
> B = number of object superclasses) of code. (A << N, B << M)

I think this is a great area for further investigation. I actually
posted a long but in retrospect pretty superficial "proposal" vaguely
along these lines several years ago (
http://www.google.com/groups?selm=19990921231807.20006.00000897%40ng-
cr1.aol.com ) . I think that mapping and categorizing the verb space
with precision on par with the object space would be a MAJOR step
forward in terms of IF programming. The problem, as zarf mentioned, is
how best to categorize the actions. My own thoughts:

I agree with zarf that a tree structure is another useful
conceptualization. I think the matrix structure you describe really
reduces to something more or less-tree like when you start to (as you
say) "leave many of the code fields blank and automatically back off to
the next highest superclass". That is, you want a verb inheritance tree
that allows verbs to inherit characteristics in the same way as objects
do.

The problem with a strict tree structure is that each verb has to
be in one place in the tree. That creates problems if you start coming
up with actions that logically share characteristics of widely-separated
places in the tree. The other problem is defining exactly how verb
inheritance is supposed to work, because breaking down actions into
discrete components is rather difficult. What does the action "hit"
involve? Do we say it involves three parts: raising your arm, extending
it quickly, and finally making contact with your target? Or do we break
it down further? And do we include "decide to hit target" as a step at
the beginning, or just the physical parts of the action? Also, if
multiple inheritance is allowed, what happens if my new verb multiply
inherits from, say, "hit" and "examine". Exactly what determines which
features of each verb are inherited into the new verb?

One thing that TADS 3 does (in a limited way) which I think may be
a step in the right direction is to abstract the idea of "preconditions"
away from the verbs. That is, you have a big set of verb
characteristics like "requires target object to visible", "requires
target object to be held", etc. When you create a new verb, you say
"ok, this verb uses preconditions X, Y and Z". This way you can sort of
put together a verb from component parts. The advantage over a tree
structure is that you have freedom to choose from the full collection of
possible combinations, instead of being restricted to just inheriting
what's available in the immediate superclass.

The reason I say this is limited in TADS 3 is that it only applies
to preconditions -- that is, criteria which must be met for the action
to be possible. It doesn't deal with things like your hit/slap/punch
hierarchy. However, it's not impossible to contemplate extending the
mechanism so that it encompasses a whole general range of semantic
features. Then hit, slap, and punch would all have, say, the "forceful
contact" semantic feature, but perhaps only slap would have the
"reprimand/insult" feature, while "punch" would have the "cause injury"
feature. Fine-tuning action responses, then, would simply be a matter
of set membership testing: to respond the same to all three actions, you
just say "does this action have the forceful contact feature?", whereas
if you want to single out slap for special handling, you additionally
ask "does it have the reprimand/insult feature?"

I've drawn this "semantic feature" terminology from linguistics,
and the theory has the same problems there as it does here in an IF
context: it's extremely difficult to pin down exactly what semantic
features describe an action to a sufficient level of detail, and to
decide exactly what constitutes "a feature". Do the features "forceful
contact" and "reprimand/insult" adequately describe a slap, or do we
need to specify something like "open palm"? Is "reprimand/insult"
really one feature, or should it be two? Or maybe it shouldn't even be
a whole feature on its own, but rather a part of some more general
feature!

In IF, the language designer who wants to create such a system also
has to keep in mind that the game programmer isn't going to want to keep
looking in the manual to remember all the semantic features. So you
have to pick a set of features that's not only sufficiently descriptive,
but also in some sense intuitive, so that the game author will be able
to more or less guess what semantic features are part of any given
action. Otherwise you have a "guess the semantic feature" puzzle for
the author.

Despite these difficulties, I do think that this is a promising
area for exploration. Up to the present, IF verb programming seems to
have been mainly concerned with the simulationally relevant mechanics of
each verb. That is, "what actual code does this verb run?". Libraries
make some concessions by including "empty slot" verbs like "blow on" or
"kiss", which by default have no real implementation, but all of these
are just singletons, floating in the verb space without any relationship
to any other verb. If we start to look at actions from a semantic
perspective, there's the potential for a much more cohesively structured
verb system.

A friend of mine and I are actually working, in a desultory manner,
on coming up with a good conceptual framework for categorizing actions
and stuff. We're really not getting anywhere as yet, but I'd be very
interested to hear some discussion of this topic, because throwing ideas
around is a good way to uncover the good ones.

--
--OKB (not okblacke)
Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is
no path, and leave a trail."
--author unknown

Mike Rozak

unread,
Feb 11, 2004, 7:15:51 PM2/11/04
to
I'll include replies to all the posts I've seen so far:

Sam Denton:


> Again, I can't speak for TADS, but this is fairly easy to do in
> Inform. For example, the default Attack action covers most of the
> verbs mentioned. An author can take some of the verbs, 'slap' and
> 'kick' for example, and pull them out of the Attack grammar and create
> Slap and Kick actions, which would then be written to use the
> AttackSub code in the default case. Fred, however, can specify a
> "before:Slap" to intercept slaps, and Mary can do the same with

> "before:kick". (Note: this is not the actual Inform syntax, but it
> gets the point across.) Or, a KnightlyNPC class, of which Fred would
> be a member, could specify a 'before:Slap' routine which would apply
> to Fred and his comrades.

Just to be picky, while inform/tads can do the same thing, it's accomplished
in a slightly different way.

Sam Denton;


> Speciallization basicly turns the full MxN matrix into a sparse
> matrix, one with many null entries. Classically, this is done via
> lists and the efficiency gains come from how one scans the lists to
> find an entry. The method used by Inform's standard library is to
> broadly classify verb-objects into their Action-classes and then to
> stick the exceptions into the objects and classes via 'before:Action'
> and 'after:Action' clauses.

Sparse matrix is a good term. The problem also reminds me of van neuman(?)
graphs used when minimizing logic for circuitry (which is also a matrix
issue).

Andrew Plotkin:


> I've had thoughts along these lines. What I really want to do is
> organize the outcomes in a tree, instead of a matrix. It would boil
> down to a sequence of branches ("Is the verb GET?" "Is the object
> heavy?" "Does the object jingle when moved?").

Another example I've seen somwhere is "ring the bell" and "hit the bell",
both causing the same result. However, "ring the monster" would not have the
same effect as "hit the monster", and "attack the bell" would act
differently than "ring the bell". I don't see this being solved nicely by a
tree. Of course, it's a rare case that can be worked around using other
means.


Andrew Plotkin:


> The fun part is coming up with an organizational scheme which lets the
> author customize the tree without having to remember the entire
> structure at once. I don't have that figured out yet. When I do,
> writing a compiler will be the easy part. :)

A GUI could be useful for this.

OKB:


> I've drawn this "semantic feature" terminology from linguistics,
> and the theory has the same problems there as it does here in an IF
> context: it's extremely difficult to pin down exactly what semantic
> features describe an action to a sufficient level of detail, and to
> decide exactly what constitutes "a feature". Do the features "forceful
> contact" and "reprimand/insult" adequately describe a slap, or do we
> need to specify something like "open palm"? Is "reprimand/insult"
> really one feature, or should it be two? Or maybe it shouldn't even be
> a whole feature on its own, but rather a part of some more general
> feature!

Oops. I have inadvertantly brought up the topic of adverbs... "politely but
firmly slap the knight". I recall seeing many posts about this in the
archives.


In general: I noticed that the replies all approach the topic from a
command-parsing direction. (This may be my fault in the way I phrased it.)
What Richard Bartle is talking about is not so much parsing of typed
commands, but the actual mechanics behind the language. (He does abutt
parsing up to this later though.)

If it is approached as a parsing issue then a skilled author can always
rewrite the IF parsing code (assuming the parsing code is in the script
language). If an author has enough cases like "ring the bell" and "slap the
knight" then the author can fix the script.

However, if it's a core feature of the language/script, then the
scripting-lanuage programmer would be the only one that could solve it, as
opposed to being solvable by the author. Seeing as I'm working on a
scripting language now, this has some relevence to me. (Note: Even if don't
impliment the Bartle solution, a script could be written to simulate it,
just as object-oriented programming can be done in C, just not as nicely.)

Mike Roberts

unread,
Feb 11, 2004, 7:35:18 PM2/11/04
to
"Andrew Plotkin" <erky...@eblong.com> wrote:
> What I really want to do is organize the outcomes in a
> tree, instead of a matrix. It would boil down to a sequence
> of branches ("Is the verb GET?" "Is the object heavy?"
> "Does the object jingle when moved?").

That's an interesting approach - it strikes me that it's basically an expert
system scheme.

One thing I'd raise that's useful about the OO approach is that it keeps the
special meanings of verbs for particular objects and classes of objects
together with those objects and classes. Human language is itself
object-oriented in this respect to some extent, in that the meanings of
verbs (and words in general) can vary so much by context, a canonical
example being TAKE PILL. This is why it tends to get kludgy to try to keep
the logic of a verb purely in the verb. In an expert-system type of
approach, you'd probably want to keep an initial OO phase that maps the verb
to an abstract action, which would then feed into the decision tree:
Object.actionFor('take') yields GetAction, while Pill.actionFor('take')
yields EatAction.

Another good thing about the OO approach is that it seems to be the ideal
way of handling the special cases that are endemic to IF. When a particular
action on a particular object has a result that's outside of what's
simulated in the world model, the OO approach lets you group the
special-case code with the involved object. Maybe there's a way to do
something similar with expert system languages. Is there such a thing as a
hybrid OO/ES language?

--Mike
mjr underscore at hotmail dot com

Sam Denton

unread,
Feb 11, 2004, 10:52:40 PM2/11/04
to
"OKB (not okblacke)" <Bren...@aol.com> wrote in message news:<Xns948C6F...@130.133.1.4>...

> I think this is a great area for further investigation. I actually
> posted a long but in retrospect pretty superficial "proposal" vaguely
> along these lines several years ago (
> http://www.google.com/groups?selm=19990921231807.20006.00000897%40ng-
> cr1.aol.com ) . I think that mapping and categorizing the verb space
> with precision on par with the object space would be a MAJOR step
> forward in terms of IF programming. The problem, as zarf mentioned, is
> how best to categorize the actions.

I'll play devil's advocate, and argue that verbs don't need as much
mapping and caregorizing as nouns do. Firstly, meaningful statistics
are hard to find, but consider this from the OED website:

"The Second Edition of the Oxford English Dictionary contains full
entries for 171,476 words in current use, and 47,156 obsolete words.
To this may be added around 9,500 derivative words included as
subentries. Over half of these words are nouns, about a quarter
adjectives, and about a seventh verbs; the rest is made up of
interjections, conjunctions, prepositions, suffixes, etc. These
figures take no account of entries with senses for different parts of
speech (such as noun and adjective)."

So, there are about 3-1/2 times as many nouns as verbs, and one can
argue that there are far, far more objects to be described by nouns
than there are distinguishable actions to be described by verbs.
Also, objects tend to use lots of adjectives with their nouns to
further distinguish themselves, while actions rarely require more that
one adverb with their verb. This means that if you were to organize a
collection of objects and a collection of actions into hierarchies
with roughtly the same number of leaves on the end-nodes, the verbs'
tree would be smaller, and more importantly, shorter.

This leads me to suspect that actions can "get by" with the ad-hoc
organization found in most IF authoring languages, while objects
benefit more from classes and inheritance.

Secondly, grammatically speaking, objects are described by a
contiguous group of words, while actions are more spread out. I can
describe a verb as "put into", but in reality the words are rarely in
proximity. Instead, one would say "I put the cat into the bag". So,
parsing is more difficult making action recognition a harder problem
in pattern recognition. It makes sense for the classification of
actions to operate in parallel with the process of recognition.

Thirdly, the matrix of verbs vs nouns is most efficiently organized as
a sparse data structure. The way things are laid out in Inform
enforces consistancy in how the matrix is represented. The
'ActionSub' routines describe actions for the uber-object, while the
specializations are found in the 'before' clauses of classes and
objects. If the specializations could also be found in a hierarchy of
actions, then you'd have an entire parallel lineage to check when
'slap George' doesn't work as expected:
Action slap
with
class attack,
before [ ; if (noun == George) {...} ];

In conclusion, I think that the current methods have been honed better
than most people suspect.

Andrew Plotkin

unread,
Feb 11, 2004, 8:52:20 PM2/11/04
to
Here, Mike Roberts <mjrUND...@hotmail.com> wrote:
> "Andrew Plotkin" <erky...@eblong.com> wrote:
> > What I really want to do is organize the outcomes in a
> > tree, instead of a matrix. It would boil down to a sequence
> > of branches ("Is the verb GET?" "Is the object heavy?"
> > "Does the object jingle when moved?").
>
> That's an interesting approach - it strikes me that it's basically
> an expert system scheme.
>
> One thing I'd raise that's useful about the OO approach is that it
> keeps the special meanings of verbs for particular objects and
> classes of objects together with those objects and classes. Human
> language is itself object-oriented in this respect to some extent,
> in that the meanings of verbs (and words in general) can vary so
> much by context, a canonical example being TAKE PILL. This is why it
> tends to get kludgy to try to keep the logic of a verb purely in the
> verb. In an expert-system type of approach, you'd probably want to
> keep an initial OO phase that maps the verb to an abstract action,
> which would then feed into the decision tree:
> Object.actionFor('take') yields GetAction, while
> Pill.actionFor('take') yields EatAction.

Right. Except that however many levels of abstraction the library
defines, I always wind up wanting to stick one in between. So that has
to be flexible.


> Another good thing about the OO approach is that it seems to be the
> ideal way of handling the special cases that are endemic to IF. When
> a particular action on a particular object has a result that's
> outside of what's simulated in the world model, the OO approach lets
> you group the special-case code with the involved object. Maybe
> there's a way to do something similar with expert system languages.

I came up with the tree idea *because* of all the special cases. It
struck me that 90% of my Inform design work consisted of defining a
condition ("Is the object a lamp?" "Does the object jingle when
moved?" etc), together with a function, stage, message, or method
which I wanted to customize when the condition held.

Give me a few months to think about it more...

Daryl McCullough

unread,
Feb 12, 2004, 10:26:55 AM2/12/04
to
Mike Roberts says...

>
>One thing I'd raise that's useful about the OO approach is that it keeps the
>special meanings of verbs for particular objects and classes of objects
>together with those objects and classes. Human language is itself
>object-oriented in this respect to some extent, in that the meanings of
>verbs (and words in general) can vary so much by context, a canonical
>example being TAKE PILL. This is why it tends to get kludgy to try to keep
>the logic of a verb purely in the verb. In an expert-system type of
>approach, you'd probably want to keep an initial OO phase that maps the verb
>to an abstract action, which would then feed into the decision tree:
>Object.actionFor('take') yields GetAction, while Pill.actionFor('take')
>yields EatAction.

That's part of Igor Melchuk's "Meaning Text Theory" of linguistics. One
of the biggest difficulties in learning a foreign language is realizing
that adjectives and nouns cannot be freely mixed. For example, if it's
raining a lot, you say that it's "raining hard" not "raining big". But
why the word "hard"? It certainly doesn't mean what "hard" means for
rocks.

If you make coffee with a lot of coffee grounds, you say it's "strong coffee"
not "heavy coffee". But "strong" certainly doesn't mean the same thing it
means when talking about weightlifters.

I've often thought that computational linguistics (particularly computer
text generation) could be put to good use in interactive fiction. Rather
than embedding text output throughout the code, you could separate two
different things:

1. The rules for how the gameworld works (as a kind of state machine).
2. The rules for describing states and state transitions.

--
Daryl McCullough
Ithaca, NY

Mike Roberts

unread,
Feb 12, 2004, 1:44:23 PM2/12/04
to
"Andrew Plotkin" <erky...@eblong.com> wrote:
> mjr:

> > Another good thing about the OO approach is that it seems to
> > be the ideal way of handling the special cases that are endemic
> > to IF.
>
> I came up with the tree idea *because* of all the special cases. It
> struck me that 90% of my Inform design work consisted of defining
> a condition ("Is the object a lamp?" "Does the object jingle when
> moved?" etc), together with a function, stage, message, or method
> which I wanted to customize when the condition held.

That's certainly been my experience as well.

What I was getting at is that the OO approach seems very good for the cases
where the *individual* object has a special case associated with it, because
you just put the special Take (or whatever) handling directly on that final,
individual object. Because it's a special case on that one object, it
doesn't matter if it's an object that jingles when moved or whatever; you as
the game designer just take all of that into account when you write that
special-case method that handles that one command on that one object.

I think what's appealing about the expert system/decision tree approach, at
least in the abstract, is that it seems to provide a better way of handling
the *semi*-special cases - questions of the sort you're using as examples,
questions that apply to broad groups that don't map directly to classes in
the inheritance hierarchy. These are the cases where the OO approach
becomes problematic, because OO wants to prioritize the overrides according
to the inheritance hierarchy. I think that's why OO libraries end up with
this proliferation of way-before/before/during/after/way-after phases, so
that a game designer has some hope of getting all the checks and actions and
consequences to execute in the right priority order. A decision tree
approach seems to offer a more structured way of ordering the execution
path, because it would more explicitly order things at the method level -
each method would code its own criteria for each branch along the code path.

The thing I'm not sure about is how well it scales. A key design problem in
constructing this kind of system would be to find a modular way of plugging
a new decision point into an existing tree. It obviously wouldn't work to
structure the trees as giant if-then-else blocks, since game authors would
have to go in and edit the library code to insert their new else-if's. I'm
also not sure that a tree is exactly what you'd want; I'd think it would end
up looking more like a graph in general, with control flowing arbitrarily
across nodes.

Anyway, all of us have enough experience with OO IF systems, and their
strengths and weaknesses, that it should be possible to get a feel for the
relative merits of a decision tree system should one come along.

Uli Kusterer

unread,
Feb 13, 2004, 4:35:08 PM2/13/04
to
In article <mwkWb.51418$Wa.4...@news-server.bigpond.net.au>,
"Mike Rozak" <Mike...@bigpond.com> wrote:

> I was looking throuh some articles in http://www.skotos.net/articles/ and
> noticed a few by Richard Batle talking about a differnt way to approach
> verb/object associations... the articles are
> http://www.skotos.net/articles/dawnof01.shtml through
> http://www.skotos.net/articles/dawnof08.shtml. (He also mentions this
> technique in the "Designing virtual worlds" books.

Hi,

note sure I understand all that guy is saying (and not sure he's too
well-informed, because C++ *does* have multiple inheritance), but IMHO
one could summarize the gist of chapter 6 as:

Instead of using "int" as the type for a player's intelligence, we
create a new class, PlayerIntelligence, which for all intents and
purposes behaves just like an "int", but which is automatically
initialized to the value "50". Is that what he's saying?

I mean, there's really nothing new about making the basic data types
classes as well. It's been done in other languages (heck, Java has
Integer objects that you can use if you want).

The second point I think the author's trying to make is that it would
be nice to also be able to inherit a method (i.e. a function attached to
an object) without an object around it. Do I understand it right?

Even if I understood the author completely wrong, I think it's a nice
idea, isn't it?

Thoughts, comments?

Cheers,
-- Uli
http://www.zathras.de

Uli Kusterer

unread,
Feb 13, 2004, 5:03:42 PM2/13/04
to
In article <kYPWb.18$Bj....@news.oracle.com>,
"Mike Roberts" <mjrUND...@hotmail.com> wrote:

> I think what's appealing about the expert system/decision tree approach, at
> least in the abstract, is that it seems to provide a better way of handling
> the *semi*-special cases - questions of the sort you're using as examples,
> questions that apply to broad groups that don't map directly to classes in
> the inheritance hierarchy. These are the cases where the OO approach
> becomes problematic, because OO wants to prioritize the overrides according
> to the inheritance hierarchy.

Permission to barge in?

Just wondering: What problem do these things solve that can't be solved
with a mix-in class instead?

Just trying to understand the things here,
-- Uli
http://www.zathras.de

Andrew Plotkin

unread,
Feb 13, 2004, 5:31:18 PM2/13/04
to
Here, Uli Kusterer <wit...@t-online.de> wrote:
> In article <kYPWb.18$Bj....@news.oracle.com>,
> "Mike Roberts" <mjrUND...@hotmail.com> wrote:
>
> > I think what's appealing about the expert system/decision tree approach, at
> > least in the abstract, is that it seems to provide a better way of handling
> > the *semi*-special cases - questions of the sort you're using as examples,
> > questions that apply to broad groups that don't map directly to classes in
> > the inheritance hierarchy. These are the cases where the OO approach
> > becomes problematic, because OO wants to prioritize the overrides according
> > to the inheritance hierarchy.
>
> Permission to barge in?

Denied. Go sit down by your squad car.

(Sorry. Emma Bull joke there, or was it Will Shetterly? Never mind.)



> Just wondering: What problem do these things solve that can't be
> solved with a mix-in class instead?
>
> Just trying to understand the things here,

(I haven't used mix-in classes, so I don't have a good seat-of-
the-pants feel for them. That said...) I think that you're correct:
a mix-in class is the way you would handle this in a pure OO system.

But classic OO seems to be a bit unwieldy for IF development. The
standard observation about one-shot classes in IF (ie, most objects
need their own subclass) applies here too. I am not keen to invent a
way to make everything I want into a class.

Mike Roberts

unread,
Feb 13, 2004, 6:11:55 PM2/13/04
to
"Uli Kusterer" <wit...@t-online.de> wrote:
> mjr:

> > I think what's appealing about the expert system/decision tree
> > approach, at least in the abstract, is that it seems to provide a
> > better way of handling the *semi*-special cases - questions of
> > the sort you're using as examples, questions that apply to broad
> > groups that don't map directly to classes in the inheritance
> > hierarchy. These are the cases where the OO approach
> > becomes problematic, because OO wants to prioritize the
> > overrides according to the inheritance hierarchy.
>
> Just wondering: What problem do these things solve that can't be
> solved with a mix-in class instead?

It's in the ordering of events. In an OO hierarchy - whether with mix-ins
or otherwise - the order of precedence for a particular method depends
entirely on the inheritance path. The order of precedence is the override
order - Person overrides Actor overrides Thing overrides Object. If you
have a mix-in, you just add a branch into the hierarchy, but you can
*always* still linearize it - you always have to be able to resolve a
hierachy down to a linear path of override precedence.

I think what's appealing about the decision-tree approach, at least
superficially, is that you can come up with the precedence rules for *each
verb*. In the OO formulation, the precedence is fixed in the hierarchy; you
can't have the Take method have one order of overriding, and the Drop method
have a different one. With a decision tree, you can. You can say: for
Take, I care first and foremost about objects that are heavy, then I care
about objects that jingle when moved, then I care about things that are
covered with glue; but for Drop, my first concern is about objects that are
being worn, then about objects that tip over easily, then about objects that
have other things inside them. You can slice and dice these group
memberships on the fly, effectively creating what would be OO classes for
the purposes of setting the precedence of your decision making, but you can
do so per decision. Am I making sense?

Uli Kusterer

unread,
Feb 13, 2004, 7:05:44 PM2/13/04
to
In article <6ZcXb.21$VW4...@news.oracle.com>,
"Mike Roberts" <mjrUND...@hotmail.com> wrote:

> It's in the ordering of events. In an OO hierarchy - whether with mix-ins
> or otherwise - the order of precedence for a particular method depends
> entirely on the inheritance path. The order of precedence is the override
> order - Person overrides Actor overrides Thing overrides Object. If you
> have a mix-in, you just add a branch into the hierarchy, but you can
> *always* still linearize it - you always have to be able to resolve a
> hierachy down to a linear path of override precedence.

So far I follow you. That's what has to happen in any OO language,
right? But since a method call must eventually be handled by *someone*,
in the end it's always a linear approach for functions, so I don't quite
get how turning an explicit (and thus transparent) linearness into an
implicit one generated from a tree would be an advantage?

> I think what's appealing about the decision-tree approach, at least
> superficially, is that you can come up with the precedence rules for *each
> verb*.

Can't you do that the way TADS does it already? I personally find it
much more readable and intuitive to just say: hitObjectWith(iobj) calls
attackObjectWith(iobj), than to have some weird multiple inheritance
scheme for methods?

> In the OO formulation, the precedence is fixed in the hierarchy; you
> can't have the Take method have one order of overriding, and the Drop method
> have a different one.

But if you had a mixin for each verb, you could, right?

> With a decision tree, you can. You can say: for
> Take, I care first and foremost about objects that are heavy, then I care
> about objects that jingle when moved, then I care about things that are
> covered with glue; but for Drop, my first concern is about objects that are
> being worn, then about objects that tip over easily, then about objects that
> have other things inside them. You can slice and dice these group
> memberships on the fly, effectively creating what would be OO classes for
> the purposes of setting the precedence of your decision making, but you can
> do so per decision. Am I making sense?

That last part I don't get. What do you mean with "I care about..." in
this context? Are we talking about determining reachability and
applicability, or are we talking about overriding built-in behavior?

If the former, I understand that moving that into classes would
probably provide for a more flexible design, without having to mess with
preconditions and similar things. But I'm not quite sure whether adding
a second kind of inheritance to functions, when we already have one for
objects, would be that useful. Personally, I'd prefer a more simple
language where classes are used for inheritance. Since classes may
contain functions, if you wanted to control things on a per-function
basis, you could simply extract that function into its own mix-in class.

Or am I still misunderstanding?
-- Uli
http://www.zathras.de

Uli Kusterer

unread,
Feb 13, 2004, 7:13:02 PM2/13/04
to
In article <c0jj7m$q55$1...@reader2.panix.com>,
Andrew Plotkin <erky...@eblong.com> wrote:

> > Permission to barge in?
>
> Denied. Go sit down by your squad car.
>
> (Sorry. Emma Bull joke there, or was it Will Shetterly? Never mind.)

Sorry, I think my list of foreign (for me) comedians only contains
Jeff Foxworthy... :-.

> (I haven't used mix-in classes, so I don't have a good seat-of-
> the-pants feel for them. That said...) I think that you're correct:
> a mix-in class is the way you would handle this in a pure OO system.
>
> But classic OO seems to be a bit unwieldy for IF development. The
> standard observation about one-shot classes in IF (ie, most objects
> need their own subclass) applies here too. I am not keen to invent a
> way to make everything I want into a class.

Well, like TADS, one could just allow declaring and instantiating a
class in one go.

But I still think I'm not getting something here...

Sighs,
-- Uli
http://www.zathras.de

Kevin Forchione

unread,
Feb 13, 2004, 8:44:53 PM2/13/04
to
"Mike Roberts" <mjrUND...@hotmail.com> wrote in message
news:6ZcXb.21$VW4...@news.oracle.com...
<snip>

> I think what's appealing about the decision-tree approach, at least
> superficially, is that you can come up with the precedence rules for *each
> verb*. In the OO formulation, the precedence is fixed in the hierarchy;
you
> can't have the Take method have one order of overriding, and the Drop
method
> have a different one. With a decision tree, you can. You can say: for
> Take, I care first and foremost about objects that are heavy, then I care
> about objects that jingle when moved, then I care about things that are
> covered with glue; but for Drop, my first concern is about objects that
are
> being worn, then about objects that tip over easily, then about objects
that
> have other things inside them. You can slice and dice these group
> memberships on the fly, effectively creating what would be OO classes for
> the purposes of setting the precedence of your decision making, but you
can
> do so per decision. Am I making sense?

Well... I wouldn't rule it out with TADS 3. You can order the hierarchy of a
TadsObject's superclasses with setSuperclassList(lst). Each verb could be
made to analyze the objects involved, and restructure their superclass lists
to fit the precedence requirements, then execute the action.

Each action would restructure the objects, but you wouldn't want to execute
code outside of an action because you'd never know what hierarchy your
object was in.

Not too difficult to set up in TADS 3, really, you'd simply modify the
Action class to handle the superclass restructuring, and assign each action
a list of precedence classes. Or... alternatively, assign each action a list
of precedence attributes, then scan each class in the object for the
appropriate attribute (i.e. isHeavy, doesJingle, etc).

--Kevin


Kevin Forchione

unread,
Feb 13, 2004, 8:53:45 PM2/13/04
to
"Kevin Forchione" <ke...@lysseus.com> wrote in message
news:p4fXb.24973$i43....@newssvr25.news.prodigy.com...

A further thought on this. You could have preinit() analyze each object and
create an origSuperclassList list and scan this for the action,
reconfiguring the objects based on the origSuperclassList. This would keep
the hierarchical precedence somewhat more stable, based on the original
author's definition. It would give each object a "default" ordering.

--Kevin


Andrew Plotkin

unread,
Feb 13, 2004, 9:40:18 PM2/13/04
to
I'll just tack comments onto this thread, since Mike is doing a better
job of explaining this than I was. :)

Here, Uli Kusterer <wit...@t-online.de> wrote:

> In article <6ZcXb.21$VW4...@news.oracle.com>,
> "Mike Roberts" <mjrUND...@hotmail.com> wrote:
>
> > It's in the ordering of events. In an OO hierarchy - whether with mix-ins
> > or otherwise - the order of precedence for a particular method depends
> > entirely on the inheritance path. The order of precedence is the override
> > order - Person overrides Actor overrides Thing overrides Object. If you
> > have a mix-in, you just add a branch into the hierarchy, but you can
> > *always* still linearize it - you always have to be able to resolve a
> > hierachy down to a linear path of override precedence.
>
> So far I follow you. That's what has to happen in any OO language,
> right? But since a method call must eventually be handled by *someone*,
> in the end it's always a linear approach for functions, so I don't quite
> get how turning an explicit (and thus transparent) linearness into an
> implicit one generated from a tree would be an advantage?

The idea (or at least the hope) is to come up with an abstraction in
which adding branches to the tree *is* explicit. And in which the
common cases are simple, but the complex cases are still possible.


> > I think what's appealing about the decision-tree approach, at least
> > superficially, is that you can come up with the precedence rules for *each
> > verb*.
>
> Can't you do that the way TADS does it already? I personally find it
> much more readable and intuitive to just say: hitObjectWith(iobj) calls
> attackObjectWith(iobj), than to have some weird multiple inheritance
> scheme for methods?

I don't know TADS notation, but what I want is a system which is
equally applicable to verbs and nouns -- or to decision trees which
mix both kinds of decision points.

(In Inform, there are about five other kinds of customization/override
mechanism begging to be replaced with the same common scheme. Once
I've got one.)

It's only weird if you insist that everything is a class, and is
governed by inheritance. That just isn't the way I write IF code, 90%
of the time.

You could look at it as an OO system where *everything* is a mix-in
class. The point is, with such a flat class system, it may not be
worth thinking of it as *classes* at all.

You certainly have to ask whether it's worth implementing it within
(or on top of) the existing [TADS/Inform] class system. If the answer
is "no", that doesn't mean it's not worth doing.

Mike Roberts

unread,
Feb 13, 2004, 9:52:35 PM2/13/04
to
"Uli Kusterer" <wit...@t-online.de> wrote:
> mjr:
> > In the OO formulation, the precedence is fixed in the hierarchy;
> > you can't have the Take method have one order of overriding,
> > and the Drop method have a different one.
>
> But if you had a mixin for each verb, you could, right?

I don't think so, but perhaps you could provide a concrete example of what
you have in mind? If we're thinking of a verb as a method, then it doesn't
matter how many mix-ins you have - the order of inheritance for *all*
methods of a given class will be the same, because it derives from the
superclass tree of the class, which is a fixed feature of the class. Mix-in
classes are fixed in that tree; they don't come and go depending on which
method you're calling.

Let me give you a concrete example. Suppose we have these classes:

Fixture - something that cannot be moved. To enforce immovability, I'm
going to define the verb handling for all of the movement-oriented verbs to
stop the command with an error, "That cannot be moved" - Take, Turn, Push,
Pull, Move, etc.

Button - a control device that causes some effect when pressed. To handle
this special effect, I'm going to define handling for the Push action to
trigger the special effect.

Now, suppose I want to create a Button that's also Fixture. If I define an
object as a composite (via multiple inheritance) of Fixture and Button - in
that order - I have a problem: Fixture.Push overrides Button.Push by virtue
of the inheritance order, so pushing the object doesn't trigger the special
effect; it just says that the object is immovable. So it's important to
define the inheritance order as Button-then-Fixture. For one thing, this
makes the combinability of these classes fragile, because you have to
remember to put things in the proper order. But the real problem comes when
some other verb common to both base classes demands that the order be
Fixture-then-Button. I don't have an example off the top of my head that
illustrates this for a Button/Fixture object, but I think it's easy to see
how this sort of conflict does come up. You could say in this case that
Button should just inherit from Fixture so this shouldn't be an issue, but
in the first place that's not necessarily clear even in this case, and in
the second place, there are many other similar cases where a
single-inheritance relationship is not at all appropriate: Containers that
are also Fixtures, Buttons that are also Readable, Fixtures that are also
Edible, etc.

In the decision-tree formulation, you avoid the problem by spelling out the
priority order of the decisions as part of the verb. "Push" asks: Is is a
button? If so, trigger its special effect. Is it fixed in place? If so,
say "That cannot be moved" and stop the command. Is it so heavy that it's
beyond the actor's strength to move? Is so, say "That's too heavy to move"
and stop the command. And so on. My hypothetical other verb that wants
things in the other order would instead ask: Is it fixed in place? If so,
do X. Is it a button? If so, do Y. Etc.

> But I'm not quite sure whether adding a second kind of inheritance
> to functions, when we already have one for objects, would be that
> useful.

Well, I wouldn't call it inheritance for functions. It's nothing that
grandiose. That's the whole point; it's just an if-then-else tree that
considers various conditions in the order that matters for the particular
verb. But that's also the weakness of the scheme, from my perspective: OO
was invented to avoid that kind of programming, because if-then-else trees
tend to become unmanageable once they grow beyond a few cases.

> Since classes may contain functions, if you wanted to control things
> on a per-function basis, you could simply extract that function into
> its own mix-in class.

I don't follow; could you give an example?

Joe Mason

unread,
Feb 13, 2004, 10:15:22 PM2/13/04
to
In article <p4fXb.24973$i43....@newssvr25.news.prodigy.com>, Kevin Forchione wrote:
> Well... I wouldn't rule it out with TADS 3. You can order the hierarchy of a
> TadsObject's superclasses with setSuperclassList(lst). Each verb could be
> made to analyze the objects involved, and restructure their superclass lists
> to fit the precedence requirements, then execute the action.

Excellent. Self-modifying code in the parser, more or less. Sounds
like a bad idea to me, really.

I think we're mixing up "inheritance" and "precedence" far too much in
this thread. An explicit delegation mechanism would be much less prone
to confusion.

Joe

Kevin Forchione

unread,
Feb 13, 2004, 11:40:47 PM2/13/04
to
"Joe Mason" <j...@notcharles.ca> wrote in message
news:slrnc2r34...@gate.notcharles.ca...

True.

But if an author changes the precedence rules for a given action, he'd have
to check and change the associated delegations in the object classes as
well. Still, it's a small price to pay for piece of mind, unless you're
masochistic...

--Kevin


Kevin Forchione

unread,
Feb 14, 2004, 12:12:58 AM2/14/04
to
"Kevin Forchione" <ke...@lysseus.com> wrote in message
news:p4fXb.24973$i43....@newssvr25.news.prodigy.com...

> Well... I wouldn't rule it out with TADS 3. You can order the hierarchy of


a
> TadsObject's superclasses with setSuperclassList(lst). Each verb could be
> made to analyze the objects involved, and restructure their superclass
lists
> to fit the precedence requirements, then execute the action.
>
> Each action would restructure the objects, but you wouldn't want to
execute
> code outside of an action because you'd never know what hierarchy your
> object was in.
>
> Not too difficult to set up in TADS 3, really, you'd simply modify the
> Action class to handle the superclass restructuring, and assign each
action
> a list of precedence classes. Or... alternatively, assign each action a
list
> of precedence attributes, then scan each class in the object for the
> appropriate attribute (i.e. isHeavy, doesJingle, etc).

The following is a demo of what I meant by the above. Compiling the code
will produce different method precedence for "push" and "take":

modify Action
{
precedenceOrder = []

/*
* Execute the action.
*/
doActionMain()
{
configureObjects();

inherited();
}

configureObjects() {}
}

modify TAction
{
/*
* Execute the action.
*/
doActionMain()
{
configureObjects();

inherited();
}
configureObjects()
{
local lst;

foreach (local info in dobjList_)
{
local obj;

obj = info.obj_;

lst = precedenceOrder.intersect(obj.origInheritanceOrder);
lst = lst.appendUnique(obj.origSuperclassList());
obj.setSuperclassList(lst);
}
}
}

PreinitObject
{
execute()
{
for (local o = firstObj(TadsObject, ObjAll); o != nil;
o = nextObj(o, TadsObject, ObjAll))
{
o.origSuperclassList = o.getSuperclassList();
o.origInheritanceOrder = o.getInheritanceOrder().toList();
}
}
}

modify Object
{
/*
* Returns a linear representation of the object's
* inheritance order from the object's flattened
* inheritance tree.
*/
getInheritanceOrder()
{
local v = new Vector(40);

// create superclass tree for this object
scTreeIter(v);

// remove any empty elements
v.removeElement(nil);

// return the result
return v;
}
scTreeIter(vector)
{
// clear any existing instances of self in the vector
vector.applyAll({x: x == self ? nil : x});

// add self to the vector
vector.append(self);

// insert the superclasses of this element into the queue
foreach (local o in getSuperclassList())
o.scTreeIter(vector);
}
}

modify TadsObject
{
origSuperclassList = []
origInheritanceOrder = []
}

modify TakeAction
{
precedenceOrder = [B, A]
}

modify PushAction
{
precedenceOrder = [A, B]
}

class A: object
{
dobjFor(Push)
{
verify() { illogical('class A Push'); }
}
dobjFor(Take)
{
verify() { illogical('class A Take'); }
}
}
class B: object
{
dobjFor(Push)
{
verify() { illogical('class B Push'); }
}
dobjFor(Take)
{
verify() { illogical('class B Take'); }
}
}

foo: A, B, Thing
'foo' 'foo' @entryway
;

--Kevin


Uli Kusterer

unread,
Feb 14, 2004, 7:23:33 AM2/14/04
to
In article <ZbgXb.22$VW4...@news.oracle.com>,
"Mike Roberts" <mjrUND...@hotmail.com> wrote:

> > But if you had a mixin for each verb, you could, right?
>
> I don't think so, but perhaps you could provide a concrete example of what
> you have in mind? If we're thinking of a verb as a method, then it doesn't
> matter how many mix-ins you have - the order of inheritance for *all*
> methods of a given class will be the same, because it derives from the
> superclass tree of the class, which is a fixed feature of the class. Mix-in
> classes are fixed in that tree; they don't come and go depending on which
> method you're calling.

Mixin classes the way I've seen them (e.g. in PowerPlant) so far
represent exactly one "ability" of an object. E.g. you'd have:

class ImmovableByPushing
push() { "can't do that."; }
;

class ImmovableByTaking
take() { "can't do that."; }
;

class MovableByPushing
push() { self.moveInto(gPlayer); }
;

class PushableButton
push() { self.setState( not self.getState() ); }
;

class Immovable : ImmovableByPushing, ImmovableByTaking
. . .
;

And whenever you define a new object you'd go

object ElevatorButton : ImmovableByTaking, PushableButton
. . .
;

If the language allowed inheriting from a class several times, wouldn't
this solve the granularity problem in a way that doesn't add yet another
complex concept to understand? And if I wanted the elevator button to be
loose, I could just mix in MovableByTaking in that particular object.

Note that, by design, a mix-in caters only to one method (or to one verb
-- I could see it having the necessary verPush() methods or whatever as
well), and has no root class, exactly so it doesn't interfere with the
rest. (okay, Immovable inherits from two classes, but it doesn't inherit
from "item" or some class like that) Am I overlooking something?

> Let me give you a concrete example. Suppose we have these classes:
>

> Now, suppose I want to create a Button that's also Fixture. If I define an
> object as a composite (via multiple inheritance) of Fixture and Button - in
> that order - I have a problem: Fixture.Push overrides Button.Push by virtue
> of the inheritance order, so pushing the object doesn't trigger the special
> effect; it just says that the object is immovable. So it's important to
> define the inheritance order as Button-then-Fixture. For one thing, this
> makes the combinability of these classes fragile, because you have to
> remember to put things in the proper order.

Well, remembering to put things in proper order. If it's not in a
class's inheritance list, it would be in the ES/tree, where you would
have to specify the order for each behavior.

> But the real problem comes when
> some other verb common to both base classes demands that the order be
> Fixture-then-Button.

Which the approach of giving each verb, heck even each "behavior" for a
verb its own mixin class would avoid.

> In the decision-tree formulation, you avoid the problem by spelling out the
> priority order of the decisions as part of the verb.

As you do in the inheritance list.

> Well, I wouldn't call it inheritance for functions. It's nothing that
> grandiose. That's the whole point; it's just an if-then-else tree that
> considers various conditions in the order that matters for the particular
> verb. But that's also the weakness of the scheme, from my perspective: OO
> was invented to avoid that kind of programming, because if-then-else trees
> tend to become unmanageable once they grow beyond a few cases.

Yes, that sounds kind of awkward. It's already hard enough in many OO
designs to find out which object of two that are interacting implements
a particular behavior. Adding decision trees to that mix sounds really
making the situation worse, IMHO.

Hope I've clarified my thoughts a bit. If you see any obvious flaws in
my thinking, let me know.

Uli Kusterer

unread,
Feb 14, 2004, 7:41:07 AM2/14/04
to
In article <c0k1qi$175$1...@reader2.panix.com>,
Andrew Plotkin <erky...@eblong.com> wrote:

> > Can't you do that the way TADS does it already? I personally find it
> > much more readable and intuitive to just say: hitObjectWith(iobj) calls
> > attackObjectWith(iobj), than to have some weird multiple inheritance
> > scheme for methods?
>
> I don't know TADS notation, but what I want is a system which is
> equally applicable to verbs and nouns -- or to decision trees which
> mix both kinds of decision points.
>
> (In Inform, there are about five other kinds of customization/override
> mechanism begging to be replaced with the same common scheme. Once
> I've got one.)

In TADS, every object has a method for reacting to a verb, and both
verbs and items are objects. I'll simplify things a little and deviate
from TADS's built-in syntax to make it more readable. E.g. when you type

POKE JEFF WITH STICK

it runs pokeVerb.hitItemWith( Jeff, Stick ), which then runs
Jeff.pokeWith(Stick), which then runs Stick.poke(Jeff). If a class
implements a particular behavior for poking something with something
else, it simply overrides one of these three methods. If all of these
methods fail, the engine outputs an error message.

Is this new approach intended to control the order of
Jeff.pokeWith(Stick) vs. Stick.poke(Jeff)?

Well, anyway, if you wanted to make "stab" a synonym for poke in this
case, you'd just write the requisite stabWith() method and have it call
pokeWith().

> It's only weird if you insist that everything is a class, and is
> governed by inheritance. That just isn't the way I write IF code, 90%
> of the time.

I don't think I understand this. Maybe you could elaborate how you
write your code as a contrast to making everything a class?

> You could look at it as an OO system where *everything* is a mix-in
> class. The point is, with such a flat class system, it may not be
> worth thinking of it as *classes* at all.
>
> You certainly have to ask whether it's worth implementing it within
> (or on top of) the existing [TADS/Inform] class system. If the answer
> is "no", that doesn't mean it's not worth doing.

Well, a (mix-in) class would roughly correspond to a feature then? Like
in my previous message to Mike? Well, on a (low-level) technical level,
I would implement both "features" and "classes" using the same
mechanisms used for classes. But if I designed my own language, it would
probably be most comprehensible if I renamed "classes" to "features" in
that case, that much is true.

But if I understand it correctly, that's not really an "alternate
programming model" so much as a different granularity for designing your
class library, is it?

Joe Mason

unread,
Feb 14, 2004, 4:43:52 PM2/14/04
to
In article <witness-468FD9...@news.t-online.com>, Uli Kusterer wrote:
> Note that, by design, a mix-in caters only to one method (or to one verb
> -- I could see it having the necessary verPush() methods or whatever as
> well), and has no root class, exactly so it doesn't interfere with the
> rest. (okay, Immovable inherits from two classes, but it doesn't inherit
> from "item" or some class like that) Am I overlooking something?

PAWS has mix-ins (I believe it calls them "services") but they're not so
fine-grained.

Just wanted to mantion that.

Joe

Mike Rozak

unread,
Feb 14, 2004, 10:44:54 PM2/14/04
to
> note sure I understand all that guy is saying (and not sure he's too
> well-informed, because C++ *does* have multiple inheritance), but IMHO
> one could summarize the gist of chapter 6 as:

I'm not sure why he stated this; it may be because the multiple inheretence
is not the right kind.


> Instead of using "int" as the type for a player's intelligence, we
> create a new class, PlayerIntelligence, which for all intents and
> purposes behaves just like an "int", but which is automatically
> initialized to the value "50". Is that what he's saying?

This is one of his suggestions, but I don't think it's the main point.


> The second point I think the author's trying to make is that it would
> be nice to also be able to inherit a method (i.e. a function attached to
> an object) without an object around it. Do I understand it right?

I read it a bit differently; he's talking about a method (aka: code) being
associated with a combination of a verb (get, attack, etc.) AND an object
(latern, monster, etc.) The exact code that's run with "get monster" is not
inhereted from the verb side, and is not inhereted from the object side, but
instead is magically determined from a combination of the classifications of
the verb AND the object. (Which is what the sparse matrix talk was about. N
verbs x M objects.) This is something that C++, Java, Inform, and TADs can't
really do; they can work around it, but the basics aren't built into the
language.

My read of the discussion tree is that some people think this (or something
similar) is an interesting idea, but in general, it's not seen as an issue
because there are plenty of workarounds.

Mike Roberts

unread,
Feb 15, 2004, 5:05:53 PM2/15/04
to
"Uli Kusterer" <wit...@t-online.de> wrote:
> Mixin classes the way I've seen them (e.g. in PowerPlant) so far
> represent exactly one "ability" of an object. E.g. you'd have:
>
> class ImmovableByPushing
> push() { "can't do that."; }
> ;
> [etc]

I don't think that's technically the definition of a mix-in (the definition
I'd use is: a class that can freely mixed, using multiple inheritance, with
classes from unrelated inheritance hierarchies), but I'd certainly agree
that this is one way you could use mix-ins.

But I'm pretty sure no one would ever actually want to write IF at this
level of granularity. Having the option to write this way is one thing -
and that's what I was saying earlier about OO doing a good job of handling
the per-instance exceptional cases, where you want to customize the handling
of a particular verb for a particular instance. But you certainly would
never want to define every one of your game instances in such a way that you
have to specify the handling of every individual action:

vase: OrdinaryTakeable, OrdinaryDroppable, OrdinaryMovable,
OrdinaryPushable, ...

The strength of the OO design is that you don't have to define your classes
by defining the individual response to every verb, but rather define them by
creating composites of recognizable real-world classes: you combine Edible
and Burnable to create a bananas flambe, or Edible and LockableWithKey and
Door to create a cheez door. The point is that you inherit the whole set of
appropriate behaviors from the real-world classes. Multiple inheritance is
an essential element of this approach because it would be prohibitive to
create a class library that pre-defines every conceivable combination of
real-world types that you'd need in any given game. The weakness of the
OO-with-multiple-inheritance approach is that any multiple inheritance
scheme has rules for inheritance precedence that sometimes (often, in
practice) produce the wrong real-world results, by picking the wrong base
class to inherit the behavior from.

> mjr:


>> For one thing, this makes the combinability of these classes fragile,
>> because you have to remember to put things in the proper order.
>
> Well, remembering to put things in proper order. If it's not in a
> class's inheritance list, it would be in the ES/tree, where you
> would have to specify the order for each behavior.

The appeal of the decision-tree approach, as Zarf pointed out, is that the
game author writes down the order of the rules *explicitly*. In the OO
approach, the inheritance precedence derives implicitly from the class
hierarchy. It's deterministic and knowable, and with a good debugger you
can trivially trace through exactly what happens when, but the fact is that
it's not something you can just easily look at in one place. My own
experience with OO libraries is that the multiple-inheritance approach
*mostly* does what you want, and *mostly* does it automatically and almost
magically, but once in a while - maybe 5% of the time - you get weird,
unexpected results. The real problem, in my experience, is that you don't
notice the unexpected results until some bizarre bug shows up in testing.

The net effect is that authors using OO libraries eventually get this uneasy
feeling about what they're doing: they know it's mostly right, but they're
never sure what they missed. I'm not at all sure the decision-tree approach
would solve that, but it would at least shift around the part that's
unknowable a bit. It might be that the decision trees in a fully elaborated
library would get so complex that they would themselves become the source of
uncertainty - authors wouldn't know exactly what to expect from certain
combinations of things without tracing through gigantic trees of
if-then-else's. And if the decision tree is modular - which I think it
would have to be allow games and library extensions to insert their
customizations - you wouldn't actually have the whole blueprint for a
decision tree in one place anyway.

Separately, Uli writes:
> E.g. when you type
>
> POKE JEFF WITH STICK
>
> it runs pokeVerb.hitItemWith( Jeff, Stick ), which then runs
> Jeff.pokeWith(Stick), which then runs Stick.poke(Jeff). If a class
> implements a particular behavior for poking something with
> something else, it simply overrides one of these three methods. If
> all of these methods fail, the engine outputs an error message.
>
> Is this new approach intended to control the order of
> Jeff.pokeWith(Stick) vs. Stick.poke(Jeff)?

No - this actually isn't what I've been talking about, anyway. What I've
been talking about is where the code for Jeff.pokeWith(stick) itself comes
from - from Jeff's Actor base class, its Thing base class, its Person base
class, or whatever else Jeff inherits from.

Kevin Forchione

unread,
Feb 15, 2004, 6:52:40 PM2/15/04
to
"Mike Roberts" <mj...@hotmail.com> wrote in message
news:53SXb.25678$OA6....@newssvr25.news.prodigy.com...

> The net effect is that authors using OO libraries eventually get this
uneasy
> feeling about what they're doing: they know it's mostly right, but they're
> never sure what they missed. I'm not at all sure the decision-tree
approach
> would solve that, but it would at least shift around the part that's
> unknowable a bit. It might be that the decision trees in a fully
elaborated
> library would get so complex that they would themselves become the source
of
> uncertainty - authors wouldn't know exactly what to expect from certain
> combinations of things without tracing through gigantic trees of
> if-then-else's. And if the decision tree is modular - which I think it
> would have to be allow games and library extensions to insert their
> customizations - you wouldn't actually have the whole blueprint for a
> decision tree in one place anyway.

This is very TADS 3 specific...

The situation is less sticky if our if-then-else decision tree is dealing
with discrete verb-object functions. If we strive for a hybrid OO/ES system
then presumably we're going to want to encapsulate object behaviors in
objects and take advantage of object inheritance. Then we have an
interesting issue of sets and subsets...

The ES.t module that I wrote for TADS 3 basically restructures an object's
superclass list for a given Action during that action's execution phase (and
then restores the original structure after the action executes). But this
approach isn't quite right. What you really want is to direct the action to
the appropriate class, but to have control then pass down that object's
inheritance hierarchy to end finally in the root-object. This would be the
case when the class indicated by the if-then-else decision tree inherits the
root class (Person, Actor, Surface, etc), but not when the indicated class
is a mix-in. In that case inheritance would move in unpredictable ways down
the object's new (and temporary) inheritance order.

For example, if we define an object as Fixture, Lightsource, Thing, what we
really want are subsets of the original object inheritance. So if our action
dictated a Lightsource precedence, we want to pass control to the object's
Lightsource methods and have them pass control down to Thing. But an action
is further complicated by it's object interactions. We may want an object to
react to a given action using a limited subset of its behaviors, but want it
to interact in that action using another subset.

If reactions were governed by actions as well the superclass restructuring
approach would be fairly clean and straightforward. Unfortunately
interactions are generally governed by direct method calls and so
interactions would be dealing the object's reaction superclass subset, which
may not be desirable.

Instead of restructuring an object's superclass list to a subset of its
inheritance list, we would probably want to pass control to delegate control
to the specific precedence class for the object. Again, this would work fine
as long as that class inherited the root class. In the case of mix-ins
control would then fall off the inheritance hierarchy of the mix-in (even
with "self" identity) and we wouldn't make it down the subset of class
inheritance to the root object. You'd have to modify the way inherited()
behaves so that delegated control to a mix-in would be picked up by the
appropriate inheritance class in the object (something like what I had to do
for multimorphic).

So, to summarize, the verb would have to scan the object's inheritance
order, based on its precedence lists (the if-then-else mechanism). It would
then have to *delegate* control to the object's selected precedence class.
And then control of inherited() flow would have to be modified so that the
inherited() mechanism correctly selected the next class in the object's
linear inheritance order. Then you would be directing control to a subset of
the object's behaviors as explicitly defined by the author/library; control
would flow correctly down the inheritance of that subset, again as
explicitly defined by the author/library; yet interactions would deal with
the object as it was originally defined, unless these interactions are
governed by new or nested actions (in which case the process of precedence
selection occurs).

NOTE: The delegated keyword *could* be made to do this kind of thing - by
passing control down to the appropriate linear inheritance ordered class of
the "self" object, instead of simply passing control down the linear
inheritance ordered classes of the object to which we are delegating. It
would then be a simple matter to code precedence lists on verb actions, and
devise a mechanism to delegate control to the appropriate class' action
methods.

--Kevin


Joe Mason

unread,
Feb 15, 2004, 8:49:40 PM2/15/04
to
In article <53SXb.25678$OA6....@newssvr25.news.prodigy.com>, Mike Roberts wrote:
> "Uli Kusterer" <wit...@t-online.de> wrote:
>> Mixin classes the way I've seen them (e.g. in PowerPlant) so far
>> represent exactly one "ability" of an object. E.g. you'd have:
>>
>> class ImmovableByPushing
>> push() { "can't do that."; }
>> ;
>> [etc]
>
> I don't think that's technically the definition of a mix-in (the definition
> I'd use is: a class that can freely mixed, using multiple inheritance, with
> classes from unrelated inheritance hierarchies), but I'd certainly agree
> that this is one way you could use mix-ins.

Not necessarily "using multiple inheritance", although that's probably
the way you'd imlpement it in C++ and similar. I know it mainly from
Ruby, which has no multiple inheritance but has a mixin as a language
construct.

What Uli's describing is a design philosophy for mixins, not an actual
definition.

Joe

ka...@henchmonkey.org

unread,
Feb 15, 2004, 9:49:19 PM2/15/04
to
Mike Roberts <mj...@hotmail.com> wrote:
[ About mix-ins ]
> [...]this is one way you could use mix-ins.

>
> But I'm pretty sure no one would ever actually want to write IF at this
> level of granularity.

[ Later, about the new ideas ]


> The appeal of the decision-tree approach, as Zarf pointed out, is that the
> game author writes down the order of the rules *explicitly*.

What do you see as the difference between specifying exactly what
finely-granular mixin classes, with precedence order, and writing the
decision-tree rules? It seems that with the decision tree, you either
are making a general case for each verb (always check takability, then
size, then ...), or you're overriding things explicitly for every
object. But you have those exact same two choices with the mix-ins. I
think the decision tree sounds interesting (although I'm still waiting
to see a usable syntax), but I'm not sure I see the difference between
the two as yet.

John

Uli Kusterer

unread,
Feb 15, 2004, 11:03:53 PM2/15/04
to
In article <slrnc306r...@gate.notcharles.ca>,
Joe Mason <j...@notcharles.ca> wrote:

> What Uli's describing is a design philosophy for mixins, not an actual
> definition.

Yeah, sorry for the inexact phrasing. I usually memorize the design
philosophy behind a construct more than the actual construct. Helps
avoid using it wrongly, so this is how it's "stored in my brain", while
I should have translated it into proper English.

Uli Kusterer

unread,
Feb 15, 2004, 11:01:32 PM2/15/04
to
In article <53SXb.25678$OA6....@newssvr25.news.prodigy.com>,
"Mike Roberts" <mj...@hotmail.com> wrote:

> of a particular verb for a particular instance. But you certainly would
> never want to define every one of your game instances in such a way that you
> have to specify the handling of every individual action:
>
> vase: OrdinaryTakeable, OrdinaryDroppable, OrdinaryMovable,
> OrdinaryPushable, ...

Fully agreed. However, you wouldn't need to. But you could inherit from
the same mix-in class a second time in most languages, I believe, which
would solve the problem just as well as messing with the inheritance
ordering of individual functions. And even if you did want to control
the order of inheritance to prevent the duplication of instance
variables, wouldn't it be more efficient to just allow that on a
per-class basis?

To summarize: There'd be a class "item" that inherits from all the
sensible action mix-ins. It'd give you all default behavior like before.
But you could just subclass it, and add a class that it already inherits
from, and the compiler would thus "pull forward" that class in the
inheritance hierarchy.

IMHO that would be a simpler solution than cooking up something entirely
new, like pre-function granularity for defining this ordering.
Specifying the order for inherited classes already exists, so why not
just expand the control over that a little?

> The appeal of the decision-tree approach, as Zarf pointed out, is that the
> game author writes down the order of the rules *explicitly*. In the OO
> approach, the inheritance precedence derives implicitly from the class
> hierarchy. It's deterministic and knowable, and with a good debugger you
> can trivially trace through exactly what happens when, but the fact is that
> it's not something you can just easily look at in one place. My own
> experience with OO libraries is that the multiple-inheritance approach
> *mostly* does what you want, and *mostly* does it automatically and almost
> magically, but once in a while - maybe 5% of the time - you get weird,
> unexpected results. The real problem, in my experience, is that you don't
> notice the unexpected results until some bizarre bug shows up in testing.

Yeah. "> screw the bear" ;-) But seriously, I fully agree. I just don't
quite agree on whether it's the right solution to add yet another
concept of inheritance.

Of course, there have been instances where people designing a language
extended an existing facility where they should have created an entirely
new concept, but I think in this case, class-level inheritance wouldn't
be abused, would it?

> No - this actually isn't what I've been talking about, anyway. What I've
> been talking about is where the code for Jeff.pokeWith(stick) itself comes
> from - from Jeff's Actor base class, its Thing base class, its Person base
> class, or whatever else Jeff inherits from.

Okay. Thanks for clarifying that. Though the other case is an
interesting problem in and of itself that bugged me a couple of times in
my feeble attempts to write an adventure way back with TADS 2...

Uli Kusterer

unread,
Feb 15, 2004, 11:11:10 PM2/15/04
to
In article <cDTXb.24096$ta7....@newssvr27.news.prodigy.com>,
"Kevin Forchione" <ke...@lysseus.com> wrote:

> But an action
> is further complicated by it's object interactions. We may want an object to
> react to a given action using a limited subset of its behaviors, but want it
> to interact in that action using another subset.
>
> If reactions were governed by actions as well the superclass restructuring
> approach would be fairly clean and straightforward. Unfortunately
> interactions are generally governed by direct method calls and so
> interactions would be dealing the object's reaction superclass subset, which
> may not be desirable.

Kevin,

could you clarify what "action" and "reaction" mean in this context? My
English isn't really up to the task of comprehending the two paragraphs
above (not a native speaker). Could you say it in simpler terms, or give
an example?

Thanks,
-- Uli
http://www.zathras.de

Uli Kusterer

unread,
Feb 15, 2004, 11:22:44 PM2/15/04
to
In article <WWBXb.56378$Wa.4...@news-server.bigpond.net.au>,
"Mike Rozak" <Mike...@bigpond.com> wrote:

> > note sure I understand all that guy is saying (and not sure he's too
> > well-informed, because C++ *does* have multiple inheritance), but IMHO
> > one could summarize the gist of chapter 6 as:
>
> I'm not sure why he stated this; it may be because the multiple inheretence
> is not the right kind.

Did his description of multiple inheritance differ somehow from C++'s?
I didn't really notice any difference. But maybe I just read it as being
C++'s, because that's the one I've used most...

> > The second point I think the author's trying to make is that it would
> > be nice to also be able to inherit a method (i.e. a function attached to
> > an object) without an object around it. Do I understand it right?
>
> I read it a bit differently; he's talking about a method (aka: code) being
> associated with a combination of a verb (get, attack, etc.) AND an object
> (latern, monster, etc.) The exact code that's run with "get monster" is not
> inhereted from the verb side, and is not inhereted from the object side, but
> instead is magically determined from a combination of the classifications of
> the verb AND the object. (Which is what the sparse matrix talk was about. N
> verbs x M objects.) This is something that C++, Java, Inform, and TADs can't
> really do; they can work around it, but the basics aren't built into the
> language.
>
> My read of the discussion tree is that some people think this (or something
> similar) is an interesting idea, but in general, it's not seen as an issue
> because there are plenty of workarounds.

I have to admit that I don't really see much of an advantage to this
verb-and-object-method. The majority of cases I've dealt with so far
(not that I'm a big IF coder, mind you) have been where one object, or
one class of objects had to react to a particular verb. So it only felt
natural to me to just stuff those things into the target object in TADS.
If that's all there is to this matrix stuff ... ?

The case where this could be more convenient would IMHO be when two
objects are used on each other. In cases where I had both "cut glass
with diamond" or "use diamond on glass", there wasn't really an object
in which the action seemed to belong. So, in this case, I would have
preferred if there had been some general action both operations would be
remapped to. I usually just moved the code in a separate function called
by both objects' action methods, but an IF language might want to tackle
that issue.

Though, as was said, these are all easily solvable, and I'm not sure
it's worth the effort to improve upon that, while there are much more
interesting problems waiting to be solved. A lot of the 80% of IF design
are still so complicated, that I don't feel it'd be too useful to deal
with the remaining 20%.

Mike Roberts

unread,
Feb 15, 2004, 11:25:20 PM2/15/04
to

<ka...@henchmonkey.org> wrote:
> What do you see as the difference between specifying exactly
> what finely-granular mixin classes, with precedence order, and
> writing the decision-tree rules?

Workload. In the mix-in-per-verb scheme, you're specifying the handling of
each verb, a la carte, per object - you're effectively specifying (objects *
verbs) different handling rules. In the decision-tree approach, you're
specifying rules per verb, but you're applying them to ad hoc groups of
objects - objects selected by arbitrary rules, some of which might be
regular OO class membership, others of which might be property value tests:
things that "jingle when moved" (Zarf's example), things weighing over 50
pounds, things that are red or green, things that are soft, etc. So you're
specifying (verbs * N) different handling rules, where N is the number of
these different ad hoc classifications you need to test per rule; N is
somewhere between 1 and the number of objects in the game, but probably much
closer to the 1 end of the scale on average.

The (verbs * N) workload is, not coincidentally, what the typical OO library
amounts to. The decision-tree approach is just a different way of slicing
the rule selection scheme.

> I think the decision tree sounds interesting (although I'm still
> waiting to see a usable syntax), but I'm not sure I see the
> difference between the two as yet.

I'm in the same boat for the first half of that - I'd need to see a concrete
formulation of the decision-tree approach before I could form an opionion
about whether this can be taken from interesting-in-principle to
usable-in-practice. But I do have a pretty clear idea of the differences
between the OO scheme and the decision-tree scheme, and there are two that I
think are key. First: in an OO system, you decide what rule to apply to
which object according to the object's class membership alone; in the
decision-tree scheme, you can use arbitrary, ad hoc criteria to select which
rules to apply to which object, based on class membership, attribute values
(weight, color, etc), and instantaneous object state (current location,
open/closed status, etc). Second: in the OO system, because rules are
selected based on class membership, rule selection is global to an object -
that is, for a given object, all rules are selected the same way, according
to the object's superclass tree. In the decision-tree scheme, each verb
decides independently which criteria to apply in what order to arrive at the
rule to apply.

Mike Roberts

unread,
Feb 15, 2004, 11:47:46 PM2/15/04
to
"Uli Kusterer" <wit...@t-online.de> wrote:
> To summarize: There'd be a class "item" that inherits from all the
> sensible action mix-ins. It'd give you all default behavior like before.
> But you could just subclass it, and add a class that it already inherits
> from, and the compiler would thus "pull forward" that class in the
> inheritance hierarchy.
>
> IMHO that would be a simpler solution than cooking up something
> entirely new, like pre-function granularity for defining this ordering.
> Specifying the order for inherited classes already exists, so why not
> just expand the control over that a little?

First, I don't think there's anything needing expansion there - I think what
you're describing could be done with the existing constructs in the existing
OO languages, and in fact I think it's the way that people actually do use
the existing OO libraries. In tads, you probably wouldn't use a mix-in
where you wanted to override the normal inheritance order for a given method
(although you could); you'd probably instead just write a copy of that
method in the object of interest, and that method would simply inherit
explicitly from the superclass of interest. It's roughly as concise as the
mix-in approach, but doesn't require the library to pre-define a mix-in for
(verbs*superclasses) cases.

Second, maybe I missed something in Zarf's posts or elsewhere, but nothing
I've been talking about involves anything new in terms of programming
methodology or language features - there's no new kind of inheritance, no
new method binding scheme, no new function granularity, no anything else
new. The thing I've been talking about is quite simple and old-fashioned,
really. It's just that the library, to execute the Take verb, would stop
doing the OO thing that it does now - schematically:

targetObject.executeTheTakeActionOnYourself();

and would instead call:

TakeAction.executeYourself(targetObject);

where TakeAction.executeYourself() is defined with code something like

if (targetObject.isJinglyWhenMoved)
doTheJinglyMoveThing(targetObject);
else if (targetObject.weight > 50)
cannotMoveHeavyThing(targetObject);
else ...;

The open question is how you set up this kind of if-then-else tree so that
(1) library extensions and game code can plug new rules into it without the
author having to hack up the library source code, and (2) it remains
straightforward for a human reading the source code to see the full
tree/network of rules, even after applying various library extensions and
game-specific additions.

Andrew Plotkin

unread,
Feb 16, 2004, 12:14:03 AM2/16/04
to
Here, Mike Roberts <mj...@hotmail.com> wrote:
> "Uli Kusterer" <wit...@t-online.de> wrote:
> > To summarize: There'd be a class "item" that inherits from all the
> > sensible action mix-ins. It'd give you all default behavior like before.
> > But you could just subclass it, and add a class that it already inherits
> > from, and the compiler would thus "pull forward" that class in the
> > inheritance hierarchy.
> >
> > IMHO that would be a simpler solution than cooking up something
> > entirely new, like pre-function granularity for defining this ordering.
> > Specifying the order for inherited classes already exists, so why not
> > just expand the control over that a little?
>
> First, I don't think there's anything needing expansion there - I think what
> you're describing could be done with the existing constructs in the existing
> OO languages, and in fact I think it's the way that people actually do use
> the existing OO libraries.

You're both right -- *everything* we've been talking about could be
implemented in an OO idiom. (It might be an ugly and verbose idiom,
though.) I'm certainly not trying to argue otherwise.

> Second, maybe I missed something in Zarf's posts or elsewhere, but nothing
> I've been talking about involves anything new in terms of programming
> methodology or language features - there's no new kind of inheritance, no
> new method binding scheme, no new function granularity, no anything else
> new. The thing I've been talking about is quite simple and old-fashioned,
> really. It's just that the library, to execute the Take verb, would stop
> doing the OO thing that it does now - schematically:
>
> targetObject.executeTheTakeActionOnYourself();
>
> and would instead call:
>
> TakeAction.executeYourself(targetObject);
>
> where TakeAction.executeYourself() is defined with code something like
>
> if (targetObject.isJinglyWhenMoved)
> doTheJinglyMoveThing(targetObject);
> else if (targetObject.weight > 50)
> cannotMoveHeavyThing(targetObject);
> else ...;

I don't want to bind this stuff to the verb *either*. One of my most
common Inform idioms is the "far away object", which rejects all verbs
except "examine". Shouldn't this have exactly the same syntax as an
"eat" verb, which rejects all objects except the tasty food?

> The open question is how you set up this kind of if-then-else tree so that
> (1) library extensions and game code can plug new rules into it without the
> author having to hack up the library source code, and (2) it remains
> straightforward for a human reading the source code to see the full
> tree/network of rules, even after applying various library extensions and
> game-specific additions.

My feeling is that you can't make this readable without starting from
scratch with a new notation.

I must be sounding like quite the revolutionary here. What I actually
is a few pages of notes and sample notation -- not even internally
consistent, much less quantifiable as rules. I think I'll shut up
until I have something to talk about.

Kevin Forchione

unread,
Feb 16, 2004, 1:40:49 AM2/16/04
to
"Mike Roberts" <mj...@hotmail.com> wrote in message
news:SXXXb.24191$_C1....@newssvr27.news.prodigy.com...

> The open question is how you set up this kind of if-then-else tree so that
> (1) library extensions and game code can plug new rules into it without
the
> author having to hack up the library source code, and (2) it remains
> straightforward for a human reading the source code to see the full
> tree/network of rules, even after applying various library extensions and
> game-specific additions.

Couldn't one use the '+' notation (or a similar notation in Inform, say) to
indicate the order of the ES objects. These being coded similarly to
ActorState objects in TADS 3, but having a simple have a checkExec() that
contains the condition, and an exec() method to do the execution: The
library then loads these into a DecisionTreeList during preinit:

For instance:

TakeAction
{
}

+DecisionTreeObject
{
checkExec()
{
return (targetObject.isJinglyWhenMoved);
}
exec()
{
doTheJinglyMoveThing(targetObject);
}
}
+DecisionTreeObject
{
checkExec()
{
return (targetObject.weight > 50);
}
exec()
{
cannotMoveHeavyThing(targetObject);
}
}
etc.

Then you have a human-readable list, and an author has merely to insert into
the list.

--Kevin


Joao Mendes

unread,
Feb 16, 2004, 1:31:05 AM2/16/04
to
Hey, all, :)

"Andrew Plotkin" <erky...@eblong.com> wrote in message
news:c0em8k$7mu$1...@reader2.panix.com...

> I came up with the tree idea...
<snip>
> Give me a few months to think about it more...

Decision trees? A starting point, in one word: Prolog.

Or more precisely, some sort of Prolog variant that would allow libraries
and allow new predicates to be created by game code or library extension
code.

But it is definitely a starting point.

Cheers,

J.


Esa A E Peuha

unread,
Feb 16, 2004, 6:52:52 AM2/16/04
to
"Mike Roberts" <mjrUND...@hotmail.com> writes:

> Let me give you a concrete example. Suppose we have these classes:
>
> Fixture - something that cannot be moved. To enforce immovability, I'm
> going to define the verb handling for all of the movement-oriented verbs to
> stop the command with an error, "That cannot be moved" - Take, Turn, Push,
> Pull, Move, etc.
>
> Button - a control device that causes some effect when pressed. To handle
> this special effect, I'm going to define handling for the Push action to
> trigger the special effect.
>
> Now, suppose I want to create a Button that's also Fixture. If I define an
> object as a composite (via multiple inheritance) of Fixture and Button - in
> that order - I have a problem: Fixture.Push overrides Button.Push by virtue
> of the inheritance order, so pushing the object doesn't trigger the special
> effect; it just says that the object is immovable. So it's important to
> define the inheritance order as Button-then-Fixture.

It strikes me that these two classes want to do very different things
with Push: Button wants to indicate that when the player types
"PUSH BUTTON", he really tries to do something other than the usual
action of pushing the button object around, while Fixture wants to
dictate that when the player actually _does_ try to push the fixture
object around, he can't. This conflict could be avoided by separating
these two uses, but I don't know how practical that would be.

--
Esa Peuha
student of mathematics at the University of Helsinki
http://www.helsinki.fi/~peuha/

Esa A E Peuha

unread,
Feb 16, 2004, 7:01:52 AM2/16/04
to
Uli Kusterer <wit...@t-online.de> writes:

> could you clarify what "action" and "reaction" mean in this context? My
> English isn't really up to the task of comprehending the two paragraphs
> above (not a native speaker). Could you say it in simpler terms, or give
> an example?

Let's say you type "HIT MIRROR" in a game. That causes the player
object to perform the action of hitting the mirror, which causes the
mirror object to perform the reaction of being hit, which causes the
mirror object to perform the action of shattering to pieces.

Andrew Plotkin

unread,
Feb 16, 2004, 11:04:50 AM2/16/04
to
Here, Joao Mendes <joao-...@netcabo.pt.invalid> wrote:
> Hey, all, :)
>
> "Andrew Plotkin" <erky...@eblong.com> wrote in message
> news:c0em8k$7mu$1...@reader2.panix.com...
>
> > I came up with the tree idea...
> <snip>
> > Give me a few months to think about it more...
>
> Decision trees? A starting point, in one word: Prolog.

Thanks, I already gouged out my eyes with Prolog back in college.

It's almost exactly not what I want for this purpose.

Mike Roberts

unread,
Feb 16, 2004, 2:35:55 PM2/16/04
to
"Andrew Plotkin" <erky...@eblong.com> wrote:
> mjr:

> > where TakeAction.executeYourself() is defined with code
> > something like
> >
> > if (targetObject.isJinglyWhenMoved)
> > doTheJinglyMoveThing(targetObject);
> > else if (targetObject.weight > 50)
> > cannotMoveHeavyThing(targetObject);
> > else ...;
>
> I don't want to bind this stuff to the verb *either*.

Yeah, I wouldn't think so - I should have said that the if-then-else tree is
what you effectively want to build, but you don't actually want to write it
that way, for the "open questions" reasons I noted (modularity,
extensibility, readability).

> One of my most common Inform idioms is the "far away
> object", which rejects all verbs except "examine". Shouldn't this
> have exactly the same syntax as an "eat" verb, which rejects all
> objects except the tasty food?

The handling I'd been thinking of for the far-away-object type of case,
where you want to handle nearly all verbs the same way for a given class, is
to use the verb-to-action mapping in the object class to map (nearly) all
verbs to some internal, generic action; you'd then isolate these sorts of
rules in that generic action's decision tree. So: Distant.verbToAction(x)
yields GenericAction unless x is 'examine', and
GenericAction.executeYourself() would check for Distant class membership
among its various if-then-else rules. But that might not actually do much
to solve the multiple-inheritance problem I've been talking about elsewhere
in the thread, as it puts part of the rule selection back into the object
hierarchy, beyond the reach of the decision tree mechanism.

It sounds like you have something else in mind here, though...

> I must be sounding like quite the revolutionary here. What I actually
> is a few pages of notes and sample notation -- not even internally
> consistent, much less quantifiable as rules. I think I'll shut up
> until I have something to talk about.

...so I guess I'll have to wait to see what you come up with in more detail.

Mike Roberts

unread,
Feb 16, 2004, 2:41:22 PM2/16/04
to
"Kevin Forchione" <ke...@lysseus.com> wrote:
> Couldn't one use the [tads 3] '+' notation (or a similar notation in

> Inform, say) to indicate the order of the ES objects.
>
> TakeAction
> +DecisionTreeObject /* jingly-when-moved rule... */ ;
> +DecisionTreeObject /* heavy rule... */ ;

> etc.
>
> Then you have a human-readable list, and an author has merely
> to insert into the list.

I think you'd need to name the DecisionTreeObjects, to allow library
extensions and user code to specify the insertion point for a new rule
relative to existing rules - you wouldn't want extensions and games to have
to physically insert code into the library source file to insert a rule
between two existing rules.

This would solve the modularity problem, but it leaves open the readability
problem, I think. The list is human-readable, but it's now distributed
around the game - once you insert a rule from game code, you can no longer
look at the library source file to see the full list of rules that'll
actually apply at run-time. It's effectively the same problem with using an
OO design, although at least the library itself could choose to isolate all
of the rules for a given action in one place.

Mike Roberts

unread,
Feb 16, 2004, 4:47:00 PM2/16/04
to
"Andrew Plotkin" <erky...@eblong.com> wrote:
> I don't want to bind this stuff to the verb *either*.

I was trying to think of what else they might be bound to, but it occurs to
me that the answer you have in mind might be "nothing." As in:

if (dobj.ofKind(Distant) && action != Examine)
...generic distant handling... ;
else if (action.involvesMoving && dobj.weight > 50)
...disallow moving something heavy... ;
else if...

(Again, modulo syntax.)

Kevin Forchione

unread,
Feb 16, 2004, 5:17:42 PM2/16/04
to
"Mike Roberts" <mjrUND...@hotmail.com> wrote in message
news:I99Yb.31$Wp3...@news.oracle.com...

> "Kevin Forchione" <ke...@lysseus.com> wrote:
> > Couldn't one use the [tads 3] '+' notation (or a similar notation in
> > Inform, say) to indicate the order of the ES objects.
> >
> > TakeAction
> > +DecisionTreeObject /* jingly-when-moved rule... */ ;
> > +DecisionTreeObject /* heavy rule... */ ;
> > etc.
> >
> > Then you have a human-readable list, and an author has merely
> > to insert into the list.
>
> I think you'd need to name the DecisionTreeObjects, to allow library
> extensions and user code to specify the insertion point for a new rule
> relative to existing rules - you wouldn't want extensions and games to
have
> to physically insert code into the library source file to insert a rule
> between two existing rules.

Definitely.

> This would solve the modularity problem, but it leaves open the
readability
> problem, I think. The list is human-readable, but it's now distributed
> around the game - once you insert a rule from game code, you can no longer
> look at the library source file to see the full list of rules that'll
> actually apply at run-time. It's effectively the same problem with using
an
> OO design, although at least the library itself could choose to isolate
all
> of the rules for a given action in one place.

That problem is going to exist in any case whether the design is OO or not,
because the moment we separate source files into "library", "extension" and
"game" we destroy the linearity of human readability. (Incidentally, the
list of rules that apply at run-time appears to be static, although it could
be dynamically modified at run-time - there's nothing that would prevent
this).

To actually see a linear human-readable list of rules that apply at run-time
would require some kind of interpreter feature that could construct a list
of source definitions corresponding to DecisionTreeObjects in the Action's
decisionTreeList. That would seem to be the case whether we had an OO design
or not. That list would have to be constructed by the 'terp at any given
point in the game, though in all probability the list would remain static
and the list could be generated when the game was loaded.

--Kevin


Kevin Forchione

unread,
Feb 16, 2004, 5:52:04 PM2/16/04
to
"Mike Roberts" <mjrUND...@hotmail.com> wrote in message
news:u%aYb.33$Wp3...@news.oracle.com...

What we are talking about are "actions" and so these decision tree objects
would seem to be naturally bound to actions, though not necessarily verbs or
simulation objects.

For TADS 3, we could accomplish this with the same '+' notation by putting
the rule under either the Action class or a GenericAction definition. You'd
want to check generic rules before Action-specific rules. For generic. You
could have rules that relate to the dobj, iobj, or even the actor - or other
game-states, so you'd want to check for the existence of an indirect object
before checking for anything specific to it.

a. If checkExec() returns true for any of the Action.decisionTreeList
objects then we exec(), stop the list iteration, and don't continue with the
specificAction.decisionTreeList.
b. Otherwise we iterate down the specificAction.decisionTreeList. If any
of those objects return true for checkExec() then we exec(), stop the list
iteration, and don't continue with normal verb processing.
c. Otherwise we proceed with normal verb processing.

In this way we have (a) actions that are not bound to specific verb-object
conditions; (b) actions that are bound to specific verb-object conditions;
(c) actions that are handled by object behaviors.

Again, humanly-readable, but the distribution is problematic - though it
always will be without 'terp or compiler support to make it otherwise.

--Kevin


Joe Mason

unread,
Feb 17, 2004, 1:18:21 AM2/17/04
to
In article <c0qpn2$218$1...@reader2.panix.com>, Andrew Plotkin wrote:
> Here, Joao Mendes <joao-...@netcabo.pt.invalid> wrote:
>> Hey, all, :)
>>
>> "Andrew Plotkin" <erky...@eblong.com> wrote in message
>> news:c0em8k$7mu$1...@reader2.panix.com...
>>
>> > I came up with the tree idea...
>> <snip>
>> > Give me a few months to think about it more...
>>
>> Decision trees? A starting point, in one word: Prolog.
>
> Thanks, I already gouged out my eyes with Prolog back in college.
>
> It's almost exactly not what I want for this purpose.

I dunno, I think it would be a fairly good syntax.

action(Verb, Dobj, Iobj) :-
Dobj.ofclass(fixeditem),
Verb.needsTake(),
actionfails {
// code for a failure
}.

Prolog's not so bad if you don't have to try and do everything with it,
Grafting a prolog interpreter onto an existing IF system at least
reduces the design to a fairly well known problem. (Although you'll
notice I've added bunches of syntax already.)

Joe

David Cornelson

unread,
Feb 17, 2004, 6:02:59 PM2/17/04
to
Andrew Plotkin <erky...@eblong.com> wrote in message >
> I must be sounding like quite the revolutionary here. What I actually
> is a few pages of notes and sample notation -- not even internally
> consistent, much less quantifiable as rules. I think I'll shut up
> until I have something to talk about.
>

I'm barging in late. Very late. I'm a terrible novice at parsers and
the nitty gritty of IF, but one of the things on the edge of my brain
for awhile has been thinking away from OO data structures.

Has anyone thought of SET logic and in particular the notations used
in multi-dimension databases? It would seem to me that using an MDDB
data structure could work to enhance the decision tree logic that
Andrew is "on the verge of" figuring out. I haven't thought too much
about what each intersection would contain in an IF-MDDB data
structure, but I do believe it's worth thinking about.

David C.

Joao Mendes

unread,
Feb 18, 2004, 11:51:10 AM2/18/04
to
Hey, all, :)

"Mike Roberts" <mjrUND...@hotmail.com> wrote in message

news:I99Yb.31$Wp3...@news.oracle.com...

Aha! Now we're talking about a different problem, to wit, source code
organization.

An odd idea: #include directives "outside" the file. Like, the main project
file might say:

File: lib.t
#include game1.t (35-45) @ 156

... or some such. The idea is that, form a human standpoint, one might look
at the source code file by file _or_ as the compiler would view it. It's all
in the IDE interface, but I'm sure it wouldn't be too hard to design a
useable one.

I hope you get what I'm scratching at. But like I said, it's a different
problem.

Cheers,

J.


Joao Mendes

unread,
Feb 18, 2004, 11:58:44 AM2/18/04