Properties and more in I7 (part 1)

168 views
Skip to first unread message

Andrew Plotkin

unread,
Sep 12, 2006, 3:11:07 PM9/12/06
to
I was originally going to title this post "I7 Purged of Every Flaw". But
someone might not realize I was kidding. What I'm actually going to do is
sketch out a scheme for unifies a lot of I7's disparate mechanisms:
properties, adjectives, kinds. It is a uniform scheme which relieves some of
the limitations of these mechanisms, while still being firmly based on the
(hopefully) familiar rule model.

This is a sweeping enough change that it probably isn't the same language
any more. This could wind up being Inform 7a, or Inform 8, or the root of an
entirely new IF system. However, for the sake of familiarity, I will discuss
it as an extension to I7, with I7-like example code and so on.

(I will also refer to "Z-machine" mechanisms, but it could be Glulx or
whatever game execution platform.)

What I am *not* addressing in this post: natural language; relations. (Well,
I'll touch on relations at the end.) I am also not dealing with the
rule-precedence topic that I've talked about in the past -- although I'll be
assuming that the compiler's rule engine *has* a way to deal with precedence
issues.

---------

** Attacking the problem: the description property

Way back in May, I opined that the use of description properties in I7 is a
bit of a historical artifact. You want to attach a textual description to
most game objects, but the natural way to do this in I7 is a set of rules:

Rule for describing a thing: say "You see nothing special."
Rule for describing a room: say "" [the default room description is blank]
...
Rule for describing the sword: say "It's an ancient Elvish sword."
Rule for describing the lamp: say "It's a battered brass lantern."
Rule for describing the lamp when the lamp is on: say "It's a
brightly-glowing brass lantern."

(One could set up this kind of description in I7 today. It would be an
extension that declared all descriptions to be "[run-describing-activity]",
a describing activity defined as above, and then a phrase "To
run-describing-activity..." Might even be worth doing, but that's not the
point of today's lecture. :)

When I first thought of this, my impulse was to throw away description
properties entirely. Do it with rules. This is my usual plan: if there are
two mechanisms that seem to serve the same purpose, one of them is
redundant.

But: if two mechanisms seem to serve the same purpose, maybe one is a
special case of the other.

Take the whole notion of an object property:

The description of the sword is "It's an ancient Elvish sword."

...and assume that this *is* a rule -- simply another phrasing of

Rule for describing the sword: say "It's an ancient Elvish sword."

(Perhaps the "describing activity" was defined with noun form "description",
so the compiler knows how to do this rephrasing.)

(Footnote: I am skipping over the distinction between a piece of text and
the action of saying that text. Maybe the description of the sword is *to
say* "It's an ancient sword." Ask me more about this later.)

Note that this neatly includes the capability of "The description of a KIND
is usually..." The rule mechanism already knows how to cope with that sort
of thing. It also lets us do stuff like "The description of X is Y *when
C*", which is new -- I7 cannot currently do that.

What else can we (currently) do with description properties? We can change
them.

Change the description of the lamp to "It's a burned-out lamp."

I don't like to write code that way, as it happens. (I'd prefer a variable
description based on some attribute.) But it's a valid thing to do. If all
descriptions are rules, how do I account for changing them in this
imperative way?

Well, the naive answer is to assume there's an implicit rule:

Rule for describing a thing (called T) when T has-been-changed-to X:
say X.

The "has-been-changed-to" condition is an internal construct -- the language
doesn't care how it's implemented. Most likely the compiler would assign a
Z-machine property for this purpose. But at this point the *language* notion
of a "property" is completely separate from Z-machine properties.

Note that this implicit rule doesn't have to affect game efficiency. In *my*
game, I'm not *going* to change any descriptions on the fly -- like I said,
it's not my style. The phrase "Change the description..." will never occur
in my game. The compiler can detect this, and decide that the implicit rule
can be entirely dropped from the rule model.

(The compiler may well be able to do smarter optimizations. If the only
"change the description" phrase in a game applies to the lamp, the implicit
rule can be restricted to "Rule for describing the lamp when..." and then
the extra if-test will only apply to the lamp. This is a level of
optimization that I7 does not currently support -- but if the rule engine
can do it, we can take advantage of it.)

Also note, by the way, these implicit rules aren't the only way to manage a
mutable description property. You could write your own description-changing
phrase, which stores the value however you want, and then have a "rule for
describing" which retrieves the value.

(This scheme lets you arbitrarily redefine the "getter" of a property.
Should we also allow the author to redefine the "setter", the implementation
of the "change P of T to V" phrase? I dunno. Probably. You tell me.)


** Extend the problem: properties containing values

Okay, this "properties are just rules" idea seems to be working out. What
other features do properties support (in current I7)? Well, properties can
store data.

The lamp has a number called the charge. The charge of the lamp is 10.
...
Change the charge of the lamp to 9.
If the lamp has a charge, ...
If the charge of the lamp is 10, ...

This is where I snuck around the point I mentioned earlier, the difference
between having some text and saying it. The description property stores
data, but really just so that it can be printed. Lots of properties aren't
like that; they genuinely store data for later retrieval.

But we can still do that, because rules can return values. (It's awkward,
but what the heck. Assume that the phrase "decide on" mechanism for
returning values, which is fairly tidy, is going to be unified with
activities and rulebooks. It's not the biggest assumption this post makes.)

What's a property? An activity for setting a value, and an activity for
getting it. If you say "The weight of a brick is 5", you're implicitly
creating the rule:

Rule for getting the weight of a brick: decide on 5.

And changing the weight is just like changing the description. *If* the game
changes a weight property, the compiler will need to allocate an internal
Z-machine property and add an implicit rule for checking it.

(The question of whether an object provides a property can be handled with
some kind of exceptional result. "Rule for getting the weight of a thing:
ain't got one.")

This is not a deep idea, but look at the nice stuff it gets us:

Computed properties. You can say "Rule for getting the weight of a solid
(S): decide on the density of S times the volume of S." The value comes from
arithmetic rather than from a "change" statement being executed -- but
that's an implementation detail. The user doesn't care. And since the rule
engine is in play, you don't even have to be homogenous about it. Some
objects could have computed weights, others have set weights. (It's IF:
exceptions will always arise.)

Properties of non-objects. What if I said:

Rule for getting the double of a number (N): decide on 2 times N.

Now, how is that any different from a computed property? N is a number as
opposed to a brick. That's the *only* difference. Of course, the compiler
will have to jump through some hoops if I then say:

Change the double of 5 to 11.

That's not *syntactically* illegal -- it's just hard to optimize! The
compiler might have to set up a hash table of changed values. Or maybe the
compiler will cry uncle. I'm okay with that. I7 already operates in a regime
where some meaningful source code fails to compile because it's too hard.
Aim for a unified language schema, and then at least we'll know where to put
new pieces as we implement them.

Oh, yes, and global variables just become properties with no arguments at
all.

I've skipped over either/or properties, but they can be handled the same way
as value properties -- as you might expect, they're value properties with
boolean values. Note that I7 already has a sort of computed boolean
property: the adjective.

Definition: A room is occupied if a person is in it.

This could as well be:

Rule for deciding whether a room (R) is occupied:
if a person is in R, decide yes;
else decide no.

(In fact I7 already has a definition syntax which employs rules, just like
this.) So great -- unify that with settable either/or properties, same trick
as before.

At this point you're probably standing on a chair and screaming, what the
hell? Adjectives are computed -- they come out of a formula! Properties can
be set or cleared at any time! How are those *the same thing*?

Because this is a rule-based system. One rule for deciding X computes a
value. Another rule for deciding X checks a stored value. The rules
conflict. Big deal -- we have mechanisms for deciding rule precedence. It's
a solved problem.

(Okay, not as solved as I'd like. But since I *do* want a better way for a
language to handle rule conflicts, I might as well want it for multiple
purposes.)

In fact, we can make a broad generalization: run-time changes take
precedence over initial conditions. If you say "now the kitchen is
occupied", it's an excellent guess that this -- the implicit value-checking
rule -- should override the rule about whether a person is there. You'll
probably want a way to wipe the stored value ("change the kitchen back to
its initial occupation condition", only less ugly) but this is a detail.

What? You in the back? You're going to ask me when it stops, right? If you
can make exceptions for "decide the double of N", why not make exceptions
for N? Redefine constants! Like in Fortran! It's crazy talk!

Not crazy at all. *IF systems redefine constants all the time.*

[Library code:]
Rule for deciding the no-go message: say "You can't go that way."

[And then, in some game's code:]
Rule for deciding the no-go message: say "Ain't gonna happen, sukka."

[And maybe at some point in the game:]
Change the no-go message to "Buzz, whirr, click."

It's a no-argument property. If you never change it, then it's a constant.
If you change it (remember, the compiler pays attention to whether you
change it), then it's a global variable. If you have a rule that computes a
value under some conditions, it's a customized bunch of rules. That's why we
like rules.

(No, you can't redefine 7. 7 is a literal, not a constant. We're not that
Fortran.)

--Z

--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*
When Bush says "Stay the course," what he means is "I don't know what to
do next." He's been saying this for years now.

Andrew Plotkin

unread,
Sep 12, 2006, 3:12:20 PM9/12/06
to

** Going for broke: kinds

What else have we got? Oh, yes, kinds.

As we noted on the newsgroup a few days ago, kinds in I7 have limitations.
(Standard example: you can't make a man who is a door. Ok, that's a silly
example. But I have encountered this in real-life game creation: I defined a
kind, and had a bunch of examples. Then I wanted to make another instance of
that kind which floated between several rooms. Not possible: my kind was not
derived from backdrop.)

The standard rules use kinds to describe groups of objects. There are rules
which apply to doors; you can put a door in your game; the rules apply to
your door. But... we already have ways to describe objects. Several ways,
which I've been trying to unify.

Say we kapoof the notion of "kinds" from the language, and instead use
either/or properties in the way I've been describing.

A thing can be a door.

Well, that's straightforward. It gives us the implicit rule:

Rule for deciding whether a thing is a door: decide no. [Things are
usually not doors.]

Create a door:

The garden gate is a door.

Implicit rule:

Rule for deciding whether the garden gate is a door: decide yes.

The rule engine easily sees that this is an exception to the general rule,
and therefore has higher precedence. Result: as expected.

Oh, sure, the compiler is going to have to optimize this. So? It had to
optimize the description property too. Heuristic: if a whole bunch of rules
for an activity hinge on what the argument object is, you should allocate a
Z-machine property. (If the rules return a boolean, allocate a Z-machine
attribute instead.) Now you can run the rules in constant time. If you're a
crazy person and you change the player into a door halfway through the game,
the compiler can still boil it down to that constant time plus an if.


** Going for broker: why kinds are hard

Now, kinds are different from either/or properties in two ways: they are
immutable, and they form an inheritance tree.

Immutability can go honk itself. If you want to change the player into a
door, go for it. The system can handle that, and (more importantly) the
system can be efficient about doorness in all the games that *don't* do
that.

Inheritance? It's certainly desirable to be able to say:

A thing can be a person. A person can be a man. A person can be a woman.
Steve is a man.

...and have the compiler realize that Steve must also be a person.

This is not merely a way to shorten your object declarations. The compiler
must also realize that the set of men is a *subset* of the set of people.
When it sees two rules:

Rule for describing a person: say "It is humanoid."
Rule for describing a man: say "Masculine!"

...it must deduce that the second rule is logically stricter than the first,
and so takes precedence. (I've spent this whole article appealing to the
rule engine to solve all my problems. I can't afford to handicap it now!)

From the top, now. The implicit rules here are:

Rule for deciding whether a thing is a person: decide no.
Rule for deciding whether a thing is a man: decide no.
Rule for deciding whether a man is a person: decide yes.
Rule for deciding whether Steve is a man: decide yes.

The third rule is the juicy one; it's implied by the declaration that a
*person* (not just anything) can be a man.

Here's the catch. The compiler is going to have to be able to evaluate these
rules -- at compile-time, I mean. Not *every* rule! Just the simplest ones:
the ones with a logical condition and a decide yes/no. The compiler is
already building decision trees, so this shouldn't be a stretch.

So when the Steve object comes along, the compiler thinks: is Steve a man? I
see two rules about that, and they're simple: the answer is clearly yes. Is
Steve a person? Two rules about *that*, and again, the answer comes out yes.

In this way, the compiler works out the membership of every *simple
immutable boolean property.* Those are our kinds, right? And then it can
simply *observe* that the set of men (in the game) is a subset of the set of
people.

Notice what I've done. A simple I7 declaration ("a man is a kind of person")
set up three different things: a subset relationship, a rule precedence
decision, and a way to declare objects.

I've broken this down into independent stages. The declaration sets up
rules. The rules are sucked into the compiler, which then lets you declare
objects based on them. The objects in turn are then observed, and the
compiler determines the subset relationship. Finally, the subset implies a
rule precedence.

Heck of a lot of extra work. The payoff: at every stage, we get
*first-class* language objects, which can be customized -- or even created
from scratch -- by the game author.

For example, the author could type those four implicit rules I quoted
earlier -- have them as *explicit* rules in his game. They would have
exactly the same effect as "A person can be a man. Steve is a man." Or, the
author could skip around the implication, and simply say "Steve is a person.
Steve is a man." Again, same effect. The subset relation is no longer
declared anywhere in the source code, but it's still *true*, so the compiler
can still correctly assess the precedence of "man" vs "person".

And we get "multiple inheritance" for free. It's not even complicated crazy
C++ multiple inheritance. Just say "Steve is a door." Now he's a door, a
person, and a man all at once. All the appropriate rules will apply --
what's the big deal?

Sure, if you have a rule for describing a man and a rule for describing a
door, they'll conflict. (Neither set is a subset of the other. So no
precedence auto-resolution.) That's what you signed up for when you created
your freakish door-man. Resolve all the conflicts (by declaring precedence
manually) and get on with the game.

The other way to make your life harder is to have more complicated rules:

Rule for deciding whether Steve is a man:
if the turn counter is even, decide yes;
else decide no.

This is a perfectly valid rule. But the compiler can't possibly work out (at
compile-time) whether Steve is a man. (Same goes if you have a "change Steve
to a man" statement somewhere in your program.) Nonetheless, as long as you
explicitly declare Steve to be a *person*, the compiler can still conclude
that "man" is a subset of "person".

Now, if you explicitly declared Steve to be a man but *not* a person, the
subset relation is no longer true. That could cause a bunch of rule
conflicts (which previously got auto-resolved) to pop to your attention.
Again, this is what you signed up for.

(By the way, the question of whether an object provides a value property is
itself a boolean property. The compiler can precompute that, if needed, in
the same way.)

Andrew Plotkin

unread,
Sep 12, 2006, 3:13:05 PM9/12/06
to

** Tricky bit: circularity

This plan has some disadvantages. Or rather, it loses some advantages of the
current I7 model. One notably nice thing about the current model is that you
have a clear layering of operations. Properties and attributes are basic:
reading them is simple, changing them is always legal and never has side
effects. Adjectives, conditions, and rules are bits of code based on the
attributes and properties.

I've thrown all that away. There are only rules. Some of the rules depend on
(internal) Z-machine properties, but most of the rules are written in terms
of each other. E.g.

Rule for deciding whether a thing is a man: decide no.
Rule for deciding whether a man is a person: decide yes.

Nothing stops you from writing circular dependencies:

Rule for deciding whether a person is a man: decide yes.

When the game tries to evaluate "if Steve is a man..." it's going to go
do-lally. Heck, the *compiler* has to evaluate whether Steve is a man --
*it's* going to go do-lally. We can't have that.

I think the compiler is going to have to do dependency checking. (Perhaps
only on the conditions of the rules, not the bodies.) If it finds a cycle,
it'll throw an error. If you use properties to emulate an inheritance tree,
there should be no cycles, so this won't bother you. Sane (non-circular)
forms of multiple inheritance will be fine also.


** Tricky bit: improper subsets

Another potential pitfall: say Steve is the only person in the game. (Ignore
the player-character for the sake of argument.) Now the set of men and the
set of people are the same thing: the singleton set of Steve. Neither is a
(proper) subset of the other.

So how can the poor compiler work out our old rule conflict?

Rule for describing a person: say "It is humanoid."
Rule for describing a man: say "Masculine!"

Rule for describing Steve: say "Steve is a hunk."

It can't decide which condition is logically stricter than the others.
Indeed, the conditions are logically *identical*.

(Note that I am precisely describing the case where the compiler is
deciding, not which rule is an *exception* to the others, but which rule
*obviates* the others. Since Steve is the only man and the only person, the
two lower-precedence rules can never execute at all.)

This situation -- identical property sets, with conflicting rules based on
each -- wouldn't arise in a simple program. The author would just define one
for his purpose. But it *will* arise in IF development, from two possible
scenarios. (1) library-defined properties (such as "man", "woman", "person")
which are used by a game -- e.g. poor Steve. (2) a game which is part-way
through development -- the author has defined the Steve object, but not yet
gotten to Linda.

I'm not sure what to make of this problem. In the case of library
properties, it may be desirable for the library to have extra precedence
hints. ("Man is a subset of person unless the author messes with stuff.") In
the case of game development, the easiest solution may be for the author to
throw in the line "Linda is a woman".


** Tricky bit: iterators

I've talked about how boolean properties can take the place of descriptions,
either/or properties, and kinds: they serve the basic purpose of answering
the question, "Is X in set S?" But conditionals are actually only one of
three ways that I7 uses descriptions. The other two are assertions ("S are
T", when defining the game world) and mutations ("Now S are T", at some
point during the game.)

(I'm mutilating Graham's discussion of sentences in the "Formal Syntax of
Sentences" example of the I7 manual.)

The upshot, anyway, is that we don't just test a specific object for
membership in S. We also have to be able to iterate over S, to carry out
tests like "if any S is T" or "if all S are T". Iteration is also necessary
for mutations: "now all S are T."

The naive implementation of iteration is: iterate over the world, testing
each object for membership. That's slow, of course. Fortunately, for many
properties -- the simple, immutable ones -- the compiler has already
computed which objects do and don't have them! So it can optimize these, by
storing arrays or linked property chains. It may be able to optimize more
complex cases as well: if a property-set S definitely contains ten objects,
and might contain five more (because those five change S during the game),
it's worth storing the list of fifteen potentials.

(As usual, it's worthwhile for the compiler to pay attention to which
iterations the game calls for. If no game operation applies to "all S",
there's no need to waste memory on a list of S objects.)


** One more tricky bit: ill-defined changes

The compiler needs to do a lot of reasoning for this system to work. This
puts some burden on the author to make sure the compiler has hard
information to work with. Mostly this means writing rules with meaningful
conditions. (Don't bury conditions as "if" statements inside rule bodies.)

A particular sore point is changes. If you write, at some point,

Change the lamp to lit.

...then the compiler will know that the lamp may or not be lit during the
course of the game. However, if you do this:

To illuminate a thing (T):
change T to lit;
say "The [T] begins to glow."

[...and then, at some point...]
Illuminate the lamp.

...then the compiler has to assume that "lit" is a completely mutable
property; any object in the game may or may not be lit at some point. Now,
that isn't a disaster -- after all, the *current* I7 "lit" property is
mutable in just this way. But you wouldn't want to accidentally make
"container" or "player-character" into mutable properties; it would make the
container/player rules hard to manage.

(Yes, *in theory*, the compiler could trace the statement "Illuminate the
lamp" down into the function. But this is a big horrible task that we don't
want to get into.)

The worst case would be if you said:

To mutate a thing (T) to a property (P):
change T to P.

At this point the compiler decides that *every property* is mutable, and the
standard library probably catches fire and burns down.


** Not going there today: Relations

Having levelled most of I7's towering skyscrapers with my death-ray, I
suppose I should turn my attention to its newest and most modern: relations.

Maybe next week.

Really, this system already overlaps the role of relations. A property which
returns something is a many-to-one relation, by definition. I7 also has
conditional relations (which I can express as computed boolean properties of
two things).

However, I7 relations go to places that my properties haven't touched:
one-to-one relations, many-to-many relations, reciprocal relations, indirect
relations. I am not going to try to encompass all that stuff. Perhaps that
stuff can be built on top of properties in a useful way. Ask me some other
time.


** Summary of this scheme:

The following I7 mechanisms all become the same thing: properties (value,
text, and either/or); adjectives; kinds of thing; global variables;
constants.

(Kinds of value are not affected by this plan. Neither are regions and
scenes, which are implemented as Z-machine objects but are not things.)

The new "property" mechanism consists, formally, of a get(...) activity and
a set(...) activity, each of which applies to zero, one, or (perhaps) more
arguments. The get(...) may either return a value or take an action
(returning nothing). (Or act *and* return, I suppose.) Each such operation
is implemented by a rule (or group of rules).

(I am assuming that phrases, actions, and activities have already been
unified!)

A property can be constant (entirely determined at compile-time) or mutable
(determined by run-time code). An explicitly-changed property is just a kind
of mutable property. A mutable property may be based on computed values,
stored values, or both.

Properties of one thing are particularly handy, because the compiler can use
Z-machine properties/attributes (of the argument) to manage them.

*Boolean* properties of one thing are treated specially. Each such property
defines a set of things, and therefore an adjective (description). Where
possible, the compiler works out (at compile-time) the properties of every
object. It then works out which sets are subsets of which other sets.

The compiler must do additional work in this scheme. It must work out
properties and subset relations, as noted above. It must also look at the
dependencies of rules, and detect cycles.

Classic I6 attributes (container, supporter, closed, transparent, door, etc)
are no longer even slightly supported. Therefore, the standard verb library
has to get rebuilt from scratch. (About time, too.)

(A minor side benefit of this: the library is no longer maintaining
"mirrored" mechanisms such as the female attribute and the woman kind, the
door attribute and the door kind, the supporter attribute and the supporter
kind, etc. There's one property for each of these.)

ChicagoDave

unread,
Sep 13, 2006, 5:04:46 PM9/13/06
to
> Andrew Plotkin wrote:

> ** Summary of this scheme:
>
> The following I7 mechanisms all become the same thing: properties (value,
> text, and either/or); adjectives; kinds of thing; global variables;
> constants.
>
> (Kinds of value are not affected by this plan. Neither are regions and
> scenes, which are implemented as Z-machine objects but are not things.)
>

So when will the beta be out?

David C.

ChicagoDave

unread,
Sep 13, 2006, 5:17:34 PM9/13/06
to
> Andrew Plotkin wrote:
>
> ** Summary of this scheme:
>
> The following I7 mechanisms all become the same thing: properties (value,
> text, and either/or); adjectives; kinds of thing; global variables;
> constants.
>

Okay - real response.

I think a pure rule-based IF system is a fantastic idea. Is it
something you just start hammering out or is it something you create a
mailing list for and start writing up details first? Some sort of
specification.

David C.

rpresser

unread,
Sep 13, 2006, 5:28:23 PM9/13/06
to

Andrew Plotkin wrote:

> For example, the author could type those four implicit rules I quoted
> earlier -- have them as *explicit* rules in his game. They would have
> exactly the same effect as "A person can be a man. Steve is a man."
> Or, the author could skip around the implication, and simply say
> "Steve is a person. Steve is a man." Again, same effect. The subset
> relation is no longer declared anywhere in the source code, but it's
> still *true*, so the compiler can still correctly assess the
> precedence of "man" vs "person".

Not exactly. "Steve is a person. Steve is a man." implies a
multiple-inheritance relation, not a subset relation, just like "Steve
is a man. Steve is a door." To get the subset relation you HAVE to
have a "A person can be a man" or "All men are persons" or something
equivalent; some way to know that there's a connection between men and
persons. Otherwise it's all multiple inheritance relations.

Am I wrong?

rpresser

unread,
Sep 13, 2006, 5:30:52 PM9/13/06
to
Here's a different way to go nuts:

Rule for determining if a thing is Steve: decide yes.

Andrew Plotkin

unread,
Sep 13, 2006, 5:44:51 PM9/13/06
to
You missed a step. You get the subset relation by looking at the
complete set of objects in the game:

Steve: person, man, flammable
Linda: person, woman
Floopies: animal, dog, poodle
brass lantern: flammable

And then "man" is *observably* a subset of "person". No attempt is made
to reason from the declarations to the subset ordering.

(This is why I put in the caveat about improper subsets. In the above
list of objects, there is nothing to tell you that "poodle" is
notionally a subset of "dog". In this game, they're the *same* set.)

> Here's a different way to go nuts:
>
> Rule for determining if a thing is Steve: decide yes.

Roger Carbol commented "Rule for determining whether something exists:
if its name is Steve, decide yes". These are both terrific ideas (at
somewhat different angles), which I'm not sure have practical value. I
frequently want to customize the definition of "door", "open/closed",
etc. I do not find myself wanting to twiddle the existence of objects
in a game, or what I (as a programmer) call them. But perhaps this is
an approach to dynamically creating game objects, in a game platform
which supports that?

--Z

--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*

If the Bush administration hasn't shipped you to Syria for interrogation, it's
for one reason: they don't feel like it. Not because of the Eighth Amendment.

Andrew Plotkin

unread,
Sep 13, 2006, 5:46:02 PM9/13/06
to

There are still enough pieces missing (e.g, the rule precedence stuff
that I've been talking about forever) that I don't see a way to start
messing with it.

--Z

--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*

Andrew Plotkin

unread,
Sep 13, 2006, 5:57:21 PM9/13/06
to
Someone brought up the point that I haven't considered the "parent",
"sibling", and "child" properties -- the relations of the world tree,
which are (of course) very heavily used in IF programming.

I7 already virtualizes these, to some extent. The I7 world relations
include "part of", which does not reside in the Z-machine world tree
at all (it's done with private Z-properties). And it successfully
integrates this with the other location properties.

So it should be entirely feasible to have a world-map model which runs
on properties, as I'm defining them here. It probably shouldn't be a
"tree" at all. Backdrops (in the I7 sense) and doors are common IF
notions of objects which are "in" multiple places at the same time.

The tricky part is a way to iterate over contents, given that there
can be several forms of "containment" (including forms that are
invented in game code).

ChicagoDave

unread,
Sep 13, 2006, 8:47:11 PM9/13/06
to
> Andrew Plotkin wrote:
> Someone brought up the point that I haven't considered the "parent",
> "sibling", and "child" properties -- the relations of the world tree,
> which are (of course) very heavily used in IF programming.
>
> I7 already virtualizes these, to some extent. The I7 world relations
> include "part of", which does not reside in the Z-machine world tree
> at all (it's done with private Z-properties). And it successfully
> integrates this with the other location properties.
>
> So it should be entirely feasible to have a world-map model which runs
> on properties, as I'm defining them here. It probably shouldn't be a
> "tree" at all. Backdrops (in the I7 sense) and doors are common IF
> notions of objects which are "in" multiple places at the same time.
>
> The tricky part is a way to iterate over contents, given that there
> can be several forms of "containment" (including forms that are
> invented in game code).

I've brought this up before and I'll keep bringing it up because I
think it's relevent to this discussion.

If you look at the usage of multi-dimension databases, you might be
able to extract some knowledge from it. For instance, a typical star
schema has fact and dimension tables. I see the facts in IF as the
authors constructs. I see the dimensions as the world model. Then you
build a cube and within the cube you can define the precedence of
intersections, filter intersections based on logic, create calculated
results, and so on. But this is just a "feeling". I'm not an expert
enough to see exactly how these two different things combine to help
IF.

I think you're on the right path. I still think the most valuable
lesson I7 has taught us is that the underlying code and interpreter
don't matter. The VM doesn't matter in the sense that a rules based NL
syntax should be able to direct its compilation to any underlying VM.

So back to rules. I think you let the author do as you mentioned. Let
them create door-man and suffer the consequences. The compiler (in the
case of MDDB's, the Cube Processor) will let them know right off the
bat that they've created a monster (figuratively and literally).

Relations would seem to me to be a pre-processing function that gets
turned into rules either at compile time or run time so it would seem
that whatever platform you build needs reflection capabilities. That's
just a feeling too.

I really like the idea of the MDDB analogy though. Given a set of
facts, here is your game, based on this library of rules.

Anyway, I see where there is a lot to be thought out here. I think one
of the reasons I bring up the mailing list idea is that there are a lot
of very smart compiler and language people out there that might be
interested in helping spark ideas to complete the process. You may not
have completed the process internally, but they might help you get
there. One of the guys that took an interest in I7 is a very serious
compiler dude, Norman Ramsey. Check out his credentials. I'm sure there
are other people.

It's worth pushing these ideas on a regular basis and who knows, maybe
all the lights turn on and IF Rules Based Development is born.

David C.

Kevin Forchione

unread,
Sep 13, 2006, 10:51:28 PM9/13/06
to
"rpresser" <rpre...@gmail.com> wrote in message
news:1158182903.2...@e3g2000cwe.googlegroups.com...

No, you're quite correct. Your example is adequate, but what we have is an
element which is a member of two sets. The relationship between those two
sets cannot be determined by those statements except to say that the
intersection of person and man contains the member Steve.

--Kevin


Jason Orendorff

unread,
Sep 14, 2006, 6:38:42 AM9/14/06
to
Andrew Plotkin wrote:
> You missed a step. You get the subset relation by looking at the
> complete set of objects in the game:
>
> Steve: person, man, flammable
> Linda: person, woman
> Floopies: animal, dog, poodle
> brass lantern: flammable
>
> And then "man" is *observably* a subset of "person". No attempt is made
> to reason from the declarations to the subset ordering.
>
> (This is why I put in the caveat about improper subsets. In the above
> list of objects, there is nothing to tell you that "poodle" is
> notionally a subset of "dog". In this game, they're the *same* set.)

Andrew, I don't follow your motivation for doing this. Why *not*
reason from the declarations? I don't know of any language that does
what you suggest instead. It seems like that's throwing away useful
information.

-j

rpresser

unread,
Sep 14, 2006, 9:19:50 AM9/14/06
to

Andrew Plotkin wrote:
> Here, rpresser <rpre...@gmail.com> wrote:

> > Not exactly. "Steve is a person. Steve is a man." implies a
> > multiple-inheritance relation, not a subset relation, just like "Steve
> > is a man. Steve is a door." To get the subset relation you HAVE to
> > have a "A person can be a man" or "All men are persons" or something
> > equivalent; some way to know that there's a connection between men and
> > persons. Otherwise it's all multiple inheritance relations.
> >
> > Am I wrong?
>
> You missed a step. You get the subset relation by looking at the
> complete set of objects in the game:

> Steve: person, man, flammable
> Linda: person, woman
> Floopies: animal, dog, poodle
> brass lantern: flammable

OK, so the compiler has to assume that there are no other persons or
men other than those defined at compile time. If part of the game is
to build an AI, then it can't be a person? You could get around that
by having the AI declared and made invisible until it is built -- which
is the normal way to do things, of course -- but it's sort of a cheat
in a way. It means that you can't infer anything about objects which
don't yet exist. Hmm, I guess I can actually accept that. If the
author needs to make statements about objects that don't yet exist, he
should make them about their "classes" by writing "Some persons are
men" rules.

> (This is why I put in the caveat about improper subsets. In the above
> list of objects, there is nothing to tell you that "poodle" is
> notionally a subset of "dog". In this game, they're the *same* set.)

Also, in that particular object list, "man" is a subset of "flammable"!
Again, this is because there are no other men... but it means that if
other men might be created dynamically (shut up, Stiffy Makane) who
won't be flammable, then you need some other rule to divorce flammable
from man. This seems like more of a gotcha than the other.

> If the Bush administration hasn't shipped you to Syria for interrogation, it's
> for one reason: they don't feel like it. Not because of the Eighth Amendment.

Rule for eligibility-for-Syria-shipment ... naah, I better not go
there; we already had the sigline flamewar this year.

Andrew Plotkin

unread,
Sep 14, 2006, 2:02:04 PM9/14/06
to

Because any given declaration can be overridden by other declarations.
You could start with a (library) declaration "A person can be a
man" but wind up with a game in which several men are *not* persons.

The ultimate answer (to whether an object has a given property) is
given by the entire mass of rules. In other words, the declarations
are a shortcut to defining rules.

If you try to reason from the declarations (or, in fact, from the list
of rules) you're introducing a second algorithm -- different from what
will happen in the game itself. If it gives the same answer, it's
redundant, and if it gives a different answer, it's wrong. I wish to
avoid this.

--Z

--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*

Andrew Plotkin

unread,
Sep 14, 2006, 2:17:06 PM9/14/06
to
Here, rpresser <rpre...@gmail.com> wrote:
>
> Andrew Plotkin wrote:
> > Here, rpresser <rpre...@gmail.com> wrote:
>
> > > Not exactly. "Steve is a person. Steve is a man." implies a
> > > multiple-inheritance relation, not a subset relation, just like "Steve
> > > is a man. Steve is a door." To get the subset relation you HAVE to
> > > have a "A person can be a man" or "All men are persons" or something
> > > equivalent; some way to know that there's a connection between men and
> > > persons. Otherwise it's all multiple inheritance relations.
> > >
> > > Am I wrong?
> >
> > You missed a step. You get the subset relation by looking at the
> > complete set of objects in the game:
>
> > Steve: person, man, flammable
> > Linda: person, woman
> > Floopies: animal, dog, poodle
> > brass lantern: flammable
>
> OK, so the compiler has to assume that there are no other persons or
> men other than those defined at compile time. If part of the game is
> to build an AI, then it can't be a person? You could get around that
> by having the AI declared and made invisible until it is built -- which
> is the normal way to do things, of course -- but it's sort of a cheat
> in a way. It means that you can't infer anything about objects which
> don't yet exist.

Since I'm starting from an Inform base, I am not thinking much about
creating objects at runtime. This is my bias, so let me set it aside.

> Hmm, I guess I can actually accept that. If the
> author needs to make statements about objects that don't yet exist, he
> should make them about their "classes" by writing "Some persons are
> men" rules.

That sounds right. If you're going to create objects after
compilation, you're going to have to define their "class" completely
at compile-time. This would probably look like a declaration of a
potential object, which then can be instantiated. (Nothing in the
system cares whether there is one object of a given rule-set, or
many.) A model of templates rather than OO classes.

(The created objects can still have variable behavior, of course, by
having conditional or stateful rules apply to them.)



> > (This is why I put in the caveat about improper subsets. In the above
> > list of objects, there is nothing to tell you that "poodle" is
> > notionally a subset of "dog". In this game, they're the *same* set.)
>
> Also, in that particular object list, "man" is a subset of "flammable"!
> Again, this is because there are no other men... but it means that if
> other men might be created dynamically (shut up, Stiffy Makane) who
> won't be flammable, then you need some other rule to divorce flammable
> from man. This seems like more of a gotcha than the other.

You would define the potential person, which would be a person, male,
not flammable. The compiler treats this like any other object, and
decides that flammability is orthogonal to personness and maleness.

Theoretically you could get rid of the "potential" idea, and allow any
object to be cloned. But the notion of whether an object can act as a
template is important enough that the compiler want to know about it
in advance, so that it can optimize. (Avoid the resource cost of
managing clonability for the whole game.)

I suppose I have to call "template" a property. And then have rules
for deciding whether X is a template... :) This is a possible argument
for having a notion of "compile-time" properties, which must be
determinable by the compiler (no computed values or runtime state).
But if I put those in, people might make important IF mechanisms be
inflexible, which would be sad. :)

--Z

--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*

Damien Neil

unread,
Sep 14, 2006, 8:39:58 PM9/14/06
to
Andrew Plotkin <erky...@eblong.com> wrote:
> Here, Jason Orendorff <jason.o...@gmail.com> wrote:
> > Andrew, I don't follow your motivation for doing this. Why *not*
> > reason from the declarations? I don't know of any language that does
> > what you suggest instead. It seems like that's throwing away useful
> > information.
>
> Because any given declaration can be overridden by other declarations.
> You could start with a (library) declaration "A person can be a
> man" but wind up with a game in which several men are *not* persons.

This sounds as if it could lead to a game author unintentionally
changing the precedence of rule.

A thing can be a human. A human can be a man. A person can be a woman.
Before kissing a human, say "You aren't that kind of girl."
Before kissing a woman, say "You don't swing that way."

Takahiro is a man. Shiba is a woman.

So far, so good. Now, far away from the above code:

Alpha is a woman. Alpha is not a human.
Kokone is a woman. Kokone is not a human.

Now there are three women and two humans in the game. "Woman" is less
specific than "human", and the precedence of the above rules has
flipped. Add in two more male humans, and the rule precedence flips
back.

There are obviously contrived elements to the above example, but I think
the general problem stands. I'm not convinced that deriving rule
precedence from a count of objects is the right way to go.

- Damien

ChicagoDave

unread,
Sep 14, 2006, 9:31:29 PM9/14/06
to
> Damien Neil wrote:
>
> A thing can be a human. A human can be a man. A person can be a woman.
> Before kissing a human, say "You aren't that kind of girl."
> Before kissing a woman, say "You don't swing that way."
> Takahiro is a man. Shiba is a woman.
> Alpha is a woman. Alpha is not a human.
> Kokone is a woman. Kokone is not a human.
>

Thing.Human
Human.Man
Person.Woman
Human.BeforeKiss, say "You aren't that kind of girl."
Woman.BeforeKiss, say "You don't swing that way."

Man.Takahiro.BeforeKiss = Human.BeforeKiss

Woman.Shiba

Woman.Alpha.BeforeKiss = Woman.BeforeKiss

!Human.Alpha

Woman.Kokone.BeforeKiss = Woman.BeforeKiss

!Human.Kokone

It's possible I'm being obtuse here, but I don't see the problem.

David C.

Andrew Plotkin

unread,
Sep 14, 2006, 11:54:50 PM9/14/06
to
Here, Damien Neil <neild-...@misago.org> wrote:
> Andrew Plotkin <erky...@eblong.com> wrote:
> > Here, Jason Orendorff <jason.o...@gmail.com> wrote:
> > > Andrew, I don't follow your motivation for doing this. Why *not*
> > > reason from the declarations? I don't know of any language that does
> > > what you suggest instead. It seems like that's throwing away useful
> > > information.
> >
> > Because any given declaration can be overridden by other declarations.
> > You could start with a (library) declaration "A person can be a
> > man" but wind up with a game in which several men are *not* persons.
>
> This sounds as if it could lead to a game author unintentionally
> changing the precedence of rule.

If you rearrange the initial "class" tree, yes, that's what would
happen. I think that's the correct behavior. When would you
unintentionally declare something to *not* be in an established class?

The compiler could generate warnings if you subvert a predefined class
relation. But I'm not sure this would be anything other than annoying.

Andrew Plotkin

unread,
Sep 15, 2006, 12:15:37 AM9/15/06
to
Here, Andrew Plotkin <erky...@eblong.com> wrote:
> Here, Damien Neil <neild-...@misago.org> wrote:
> > Andrew Plotkin <erky...@eblong.com> wrote:
> > > Here, Jason Orendorff <jason.o...@gmail.com> wrote:
> > > > Andrew, I don't follow your motivation for doing this. Why *not*
> > > > reason from the declarations? I don't know of any language that does
> > > > what you suggest instead. It seems like that's throwing away useful
> > > > information.
> > >
> > > Because any given declaration can be overridden by other declarations.
> > > You could start with a (library) declaration "A person can be a
> > > man" but wind up with a game in which several men are *not* persons.
> >
> > This sounds as if it could lead to a game author unintentionally
> > changing the precedence of rule.
>
> If you rearrange the initial "class" tree, yes, that's what would
> happen. I think that's the correct behavior. When would you
> unintentionally declare something to *not* be in an established class?

Let me note that the standard library, as currently constituted,
doesn't have any rules that are defined differently for "person" and
"man"/"woman"/"animal". So this particular case is fictive, if that
makes any difference to your intuition of correct behavior.

The most likely case I can think of for a library subclass-relation
that might be broken in a particular game: "player-character" and
"person". (If a game had a potential player-object which was an animal
or inanimate.) But in this case, I'd think the author would *want* to
review all the rules that conflict in those cases.

Damien Neil

unread,
Sep 15, 2006, 2:55:50 AM9/15/06
to
Andrew Plotkin <erky...@eblong.com> wrote:
> Let me note that the standard library, as currently constituted,
> doesn't have any rules that are defined differently for "person" and
> "man"/"woman"/"animal". So this particular case is fictive, if that
> makes any difference to your intuition of correct behavior.

I'm less worried about the standard library than normal authors' code.
The standard library can always be coded with the most robust checks,
specifications, and so forth. It will be written by people with a very
strong understanding of the core language, and undergo constant stress
testing in common usage.

But I can see someone producing something like the example I gave above.
Is it so unlikely that someone might define an inheritance hierarchy
while subverting it in specified objects?

- Damien

Andrew Plotkin

unread,
Sep 15, 2006, 11:21:14 AM9/15/06
to
Here, Damien Neil <neild-...@misago.org> wrote:

Yes, I think it is unlikely. (Honest.) I envisioned this model mostly
as a way to provide variable or computed "classes" for objects. That
is: the common use of this would be to have an object which sometimes
is a man (and person), and sometimes neither. Or an object which
sometimes is a man, but always is a person. An object which is a man,
but not a person, is an odder -- er -- kettleless kettle of fish.

Furthermore, I think that if you subvert an inheritance hierarchy,
you're doing it for a specific reason. You're saying, ok, in this
game, not all men are people. Ok. So why should the compiler assume
that:

If X is a man: ...

takes precedence over (is an exception to)

If X is a person: ...

for the men that *are* people? The concepts have been partially
unscrewed from each other. This relationship therefore requires
authorial attention.

Keep in mind that I am assuming a robust precedence mechanism. The
author will have the opportunity to say that the first rule takes
precedence. I am only saying that the compiler should no longer
*assume* it from the game structure.

(I am also envisioning an object browser that shows subset relations
as a graph. When the rule conflict is brought to your attention, it
can pop up that part of the graph: see, Linda is a person but not a
man, and R. Daneel is a man but not a person. That's what's going on
here. What do you want to do about it?)

--Z

--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*

If the Bush administration hasn't thrown you in military prison without trial,
it's for one reason: they don't feel like it. Not because you're patriotic.

Adam Thornton

unread,
Sep 16, 2006, 2:25:04 PM9/16/06
to
In article <1158239990.0...@i42g2000cwa.googlegroups.com>,
"rpresser" <rpre...@gmail.com> wrote:
> Rule for eligibility-for-Syria-shipment ...

Well, at least the Bush administration has made THIS one easy to code.

Rule for eligibility-for-Syrria-shipment: yes.

Adam

Jason Orendorff

unread,
Sep 18, 2006, 11:34:32 AM9/18/06
to
Andrew Plotkin wrote:
> Here, Jason Orendorff <jason.o...@gmail.com> wrote:
> > Andrew Plotkin wrote:
> > > And then "man" is *observably* a subset of "person". No attempt is made
> > > to reason from the declarations to the subset ordering.
> >
> > Andrew, I don't follow your motivation for doing this. Why *not*
> > reason from the declarations? [...]

>
> Because any given declaration can be overridden by other declarations.
> You could start with a (library) declaration "A person can be a
> man" but wind up with a game in which several men are *not* persons.

I think I see now, maybe.

> The ultimate answer (to whether an object has a given property) is
> given by the entire mass of rules. In other words, the declarations
> are a shortcut to defining rules.

Actually, the ultimate answer is available only at run time. Should
rule precedence shift at run time if the properties of objects change?

> If you try to reason from the declarations (or, in fact, from the list
> of rules) you're introducing a second algorithm -- different from what
> will happen in the game itself. If it gives the same answer, it's
> redundant, and if it gives a different answer, it's wrong.

I am a little uncertain about the meaning of this; I feel I may not
have understood the *first* algorithm, i.e. "what will happen in the
game itself".

Generally, it sounds like you've chosen a particular algorithm which is
easy to describe, but sounds like it would be unintuitive in practice.
I think this means the algorithm is unsuitable. The particular fault,
it seems to me, is that it depends on something dynamic and global to
determine something that is critical for local reasoning about code.
Something trivial like "Rules are applied in the order they appear in
the source", combined with compiler warnings when a rule is completely
eclipsed, seems preferable.

[j]

Kevin Forchione

unread,
Sep 18, 2006, 12:38:42 PM9/18/06
to
"Jason Orendorff" <jason.o...@gmail.com> wrote in message
news:1158593672.5...@e3g2000cwe.googlegroups.com...

> Andrew Plotkin wrote:
>> Here, Jason Orendorff <jason.o...@gmail.com> wrote:
>> > Andrew Plotkin wrote:
>> > > And then "man" is *observably* a subset of "person". No attempt is
>> > > made
>> > > to reason from the declarations to the subset ordering.
>> >
>> > Andrew, I don't follow your motivation for doing this. Why *not*
>> > reason from the declarations? [...]
>>
>> Because any given declaration can be overridden by other declarations.
>> You could start with a (library) declaration "A person can be a
>> man" but wind up with a game in which several men are *not* persons.
>
> I think I see now, maybe.
>
>> The ultimate answer (to whether an object has a given property) is
>> given by the entire mass of rules. In other words, the declarations
>> are a shortcut to defining rules.
>
> Actually, the ultimate answer is available only at run time. Should
> rule precedence shift at run time if the properties of objects change?

A little rambling thought...

I find myself wondering, as a kind of peripheral issue, that a more dynamic
environment may be what's needed. If I'm understanding Andrew correctly,
what he's ultimately talking about is the definition of a set of
relationships that dynamically define the ... class... of an entity through
their participation in various sets, rather than through static declaration.
If that is the case then compilation probably wouldn't be sufficient for
this definition, since participation might shift during game play. Unless of
course, one mandates that the class of an entity is determined at compile
time.

I'm not sure that the rule precedence would shift at runtime, however, since
the entities on which they are acting would be merely shifting identities.
In other words, the rules precedence for handling various classes of entity
are in a sense the framework of meaning within the program. They might be
dynamically altered during runtime, but this probably would not be the
result of a change of affiliation of an entity from one class to another.
Rather a change in the rules precedence during game play would signify a
change in the meaning of the game at that point in time. In that sense the
rules become entities for which their precedence order provides a kind of
meaning.

The other thing that is of interest to me is the nature of this
rule/relationship entity. It seems that we're talking about a new kind of
datatype that is a hybrid in that in certain cases we are looking at a
relationship (i.e. man(Steve)) and in other cases a rule for determining
what to do (i.e. insteadOf(Eating(Apple), DropDead(Player))). The
relationship and the rule do not seem so distinct to me, though of course
I've been a little mad lately.

--Kevin

--Kevin


Kevin Forchione

unread,
Sep 18, 2006, 12:46:37 PM9/18/06
to
"Kevin Forchione" <ke...@lysseus.com> wrote in message
news:iYzPg.9638$cw.513@fed1read03...

> The other thing that is of interest to me is the nature of this
> rule/relationship entity. It seems that we're talking about a new kind of
> datatype that is a hybrid in that in certain cases we are looking at a
> relationship (i.e. man(Steve)) and in other cases a rule for determining
> what to do (i.e. insteadOf(Eating(Apple), DropDead(Player))). The
> relationship and the rule do not seem so distinct to me, though of course
> I've been a little mad lately.

As a point of clarification, suppose the datatype for this concept were
defined something like this:

RelationRule(entity1, entity2, entity3) <= relationship representation
{
// rule representation
}

Then a pure relationship would have an empty rule code-block. A rule, it
seems is an extension of relationship, although perhaps a rule might have no
entities. Beyond this my thoughts are not at all clear. However, I have
begun to play around with some of this a little, and who knows?

--Kevin


steve....@gmail.com

unread,
Sep 18, 2006, 1:15:26 PM9/18/06
to
Andrew Plotkin wrote:
> I'd think the author would *want* to
> review all the rules that conflict in those cases.

I think the big issue with rules is precedence, and I think the obvious
solution is the one you've presented several times in the past: a
compiler which, rather than assuming some order, identifies conflicts
and interacts with the coder to resolve the conflicts.

I personally don't really like logic programming, but if that's what
one is doing, that seems the way to go.

steve....@gmail.com

unread,
Sep 18, 2006, 1:52:41 PM9/18/06
to
Kevin Forchione wrote:

> Jason Orendorff wrote:
> > Actually, the ultimate answer is available only at run time. Should
> > rule precedence shift at run time if the properties of objects change?
>
> I find myself wondering, as a kind of peripheral issue, that a more dynamic
> environment may be what's needed. If I'm understanding Andrew correctly,
> what he's ultimately talking about is the definition of a set of
> relationships that dynamically define the ... class... of an entity through
> their participation in various sets, rather than through static declaration.
> If that is the case then compilation probably wouldn't be sufficient for
> this definition, since participation might shift during game play. Unless of
> course, one mandates that the class of an entity is determined at compile
> time.

You wouldn't need to require that the class of the object be
permanently determined at compile time. You'd just have the initial
class of the object determined at compile time to the extent necessary,
and it would be available to dynamic updating at runtime.

> I'm not sure that the rule precedence would shift at runtime, however, since
> the entities on which they are acting would be merely shifting identities.
> In other words, the rules precedence for handling various classes of entity
> are in a sense the framework of meaning within the program.

'Meaning' is a bad term. But I think you're saying that the 'rules' are
the static bit, and the objects (or 'entities' as you put it) are the
dynamic bit.

> They might be
> dynamically altered during runtime, but this probably would not be the
> result of a change of affiliation of an entity from one class to another.

So, you're saying that the rules could be altered, but on a separate
level to object superclass switching.

Let's think for a second why the TADS 3 mechanism for switching
superclass is almost never used. An object defines its behavior, and
can do so based on runtime data. So, as the runtime data changes, so
does its behavior, by design. Rarely (if ever) do you want an object to
change its overall strategy for dealing with the runtime situation, to
become another class.

The behavior defined by the object can be abstracted (or re-organized)
into rules, but the same practical situation obtains. You will rarely
want to remove it from one set of rules and place it within the bounds
of another group of rules.

> Rather a change in the rules precedence during game play would signify a
> change in the meaning of the game at that point in time.

Again, 'meaning' is the wrong word. Do you mean 'runtime data'?

> In that sense the
> rules become entities for which their precedence order provides a kind of
> meaning.

Precedence is just the order of operations. You can indeed alter the
result/effect ('meaning' if you wish) of a rule by altering its place
in the precedence order.

> The other thing that is of interest to me is the nature of this
> rule/relationship entity. It seems that we're talking about a new kind of
> datatype that is a hybrid in that in certain cases we are looking at a
> relationship (i.e. man(Steve)) and in other cases a rule for determining
> what to do (i.e. insteadOf(Eating(Apple), DropDead(Player))). The
> relationship and the rule do not seem so distinct to me, though of course
> I've been a little mad lately.

These examples are syntactically similar looking, but totally different
in behavior. The declaration of relationship is a statement which can
be asserted wherever you like, while the rule must somehow hook into
the program flow.

Kevin Forchione

unread,
Sep 18, 2006, 2:31:58 PM9/18/06
to
<steve....@gmail.com> wrote in message
news:1158601961.6...@h48g2000cwc.googlegroups.com...

Agreed. I'm not saying I'd recommend it.

>> Rather a change in the rules precedence during game play would signify a
>> change in the meaning of the game at that point in time.
>
> Again, 'meaning' is the wrong word. Do you mean 'runtime data'?
>
>> In that sense the
>> rules become entities for which their precedence order provides a kind of
>> meaning.
>
> Precedence is just the order of operations. You can indeed alter the
> result/effect ('meaning' if you wish) of a rule by altering its place
> in the precedence order.

That's what I've been getting at. If you change the traditional precedence
of arithmetic operations, for instance, you change the result effect of the
operations. I've been using "meaning" in that sense. I can't conceive of a
reason why you would want to change precedence dynamically, though in
practice as soon as something like that is restricted someone will think of
a reason why they want to do it.

>> The other thing that is of interest to me is the nature of this
>> rule/relationship entity. It seems that we're talking about a new kind of
>> datatype that is a hybrid in that in certain cases we are looking at a
>> relationship (i.e. man(Steve)) and in other cases a rule for determining
>> what to do (i.e. insteadOf(Eating(Apple), DropDead(Player))). The
>> relationship and the rule do not seem so distinct to me, though of course
>> I've been a little mad lately.
>
> These examples are syntactically similar looking, but totally different
> in behavior. The declaration of relationship is a statement which can
> be asserted wherever you like, while the rule must somehow hook into
> the program flow.

Yes, agreed, the behaviors are different as you point out, and perhaps I'm
mixing apples and oranges. Yet it seems the two ought to be fused in some
fashion such that for a given relationship there may exist an associated
rule. Doubtless I've got a long way to go in my thinking, though, but I'll
push it and see how far it goes!

--Kevin


Andrew Plotkin

unread,
Sep 18, 2006, 2:59:10 PM9/18/06
to

I was not envisioning the rule precedence ever shifting at runtime.

(Perhaps you could conditionalize a rule precedence declaration --
"rule X has precedence over rule Y when the door is closed" -- but
this is a far-reach feature and I wouldn't put it in unless someone
made a very clear case for needing it. In fact, this is one area where
I think I7 is *too* flexible: I7 procedural rules allow this kind of
thing, and it makes it really hard for the compiler to do any kind of
reasoning about the rule structure.)

It may help to think of this subset relation as creating, not a
precedence relation, but a *default* precedence relation. The compiler
is using it as a hint to set up the rule ordering -- a labor-saving
device. As a hint, we'd like it to be correct most of the time, but
it's okay to give up (sometimes) or get it wrong (rarely), because the
author is making the final decision.

So if the "person" and "man" properties of an object both change at
runtime, then compiler will probably decide that it just doesn't know
what the precedence relation should be between "person" and "man"
rules. The author gets to make that decision, because he's doing
something weird.

And hopefully it will be a one-line, write-once-and-stop-worrying sort
of decision. (If the author has to twiddle ten different rule
declarations because of one funny ambisexual object, that's a bad
situation.)

> The other thing that is of interest to me is the nature of this
> rule/relationship entity. It seems that we're talking about a new kind of
> datatype that is a hybrid in that in certain cases we are looking at a
> relationship (i.e. man(Steve)) and in other cases a rule for determining
> what to do (i.e. insteadOf(Eating(Apple), DropDead(Player))). The
> relationship and the rule do not seem so distinct to me, though of course
> I've been a little mad lately.

Well, they're two slightly different uses of the same mechanism: one
returns a boolean, the other returns nothing but takes action. Very
much analogous to "functions" and "procedures", which are unified in
almost all computer languages.

The new data type... isn't really a data type, and in your examples
it's really "man", "eating", and "dropdead" which are analogus.
"instead of" is a *declaration about a rule*, not itself a rule.

--Z

--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*

If the Bush administration hasn't subjected you to searches without a warrant,
it's for one reason: they don't feel like it. Not because you're an American.

Andrew Plotkin

unread,
Sep 18, 2006, 11:20:55 PM9/18/06
to
Here, Andrew Plotkin <erky...@eblong.com> wrote:
>
> > The other thing that is of interest to me is the nature of this
> > rule/relationship entity. It seems that we're talking about a new kind of
> > datatype that is a hybrid in that in certain cases we are looking at a
> > relationship (i.e. man(Steve)) and in other cases a rule for determining
> > what to do (i.e. insteadOf(Eating(Apple), DropDead(Player))). The
> > relationship and the rule do not seem so distinct to me, though of course
> > I've been a little mad lately.
>
> Well, they're two slightly different uses of the same mechanism: one
> returns a boolean, the other returns nothing but takes action. Very
> much analogous to "functions" and "procedures", which are unified in
> almost all computer languages.
>
> The new data type... isn't really a data type, and in your examples
> it's really "man", "eating", and "dropdead" which are analogus.
> "instead of" is a *declaration about a rule*, not itself a rule.

After an evening's consideration, I have decided that my answer was
confusing and wrong. (Perhaps you have decided the same. :) Let me
back up and describe terminology.

I say that any true rule-based model will boil down to *exactly one*
form of rule declaration:

[When CONDITION:] Instead of IDENTIFIER, do CODE.

(If the CONDITION is absent, read "always".) Before/after declarations
can be rearranged into this form.

Retracting my earlier answer, I will call this declaration "a rule".

(*Precedence* declarations are a different kind of thing, which I have
various ideas about how to define. Contradictory ideas. :)

Now we have to decide what to call the IDENTIFIER (or what it
identifies). In I7 terms it's a "rulebook", except it's also an
"activity" or "phrase" -- these being different language mechanisms
which are defined by sets of rules. I will go with "rulebook" here,
with the understanding that I kind of hate that term and may switch to
something else later.

So: "man", "eating", and "dropdead" are rulebooks (which can be
called from code). Each is defined by various rules. One such rule is

When noun is Apple: instead of Eating, call Dropdead(Player).

(One could theoretically turn the IDENTIFIER into simply another
condition! Then this would be

When noun is Apple and rulebook is Eating:
call(rulebook=Dropdead, noun=Player).

Note that this language only has one statement: call()! That is, as
far as I'm concerned, too much of a good thing. So forget it.)

The fun questions: is a rule a kind of rulebook? Is a rulebook a kind
of rule?

(I7 answers "no; yes".)

To rephrase this in more immediate terms: can you say "Instead of R..."
where R is any specific rule? Or can you only instead-of a general
rulebook, which has a platonic existence above all the rules that
define its behavior?

The latter answer is, obviously, simpler. There are rules and
rulebooks, and they exist on different levels; never confuse them.

I am not sure I like the simple answer. Here's why: assume the
compiler has figured out the precedence order for all the rules R1,
R2, R3, ... in a rulebook. It can then generate code that looks (sans
optimizations) like:

if (cond1) { code1 }
else if (cond2) { code2 }
else if (cond3) { code3 }
...

(There may be some don't-cares in the precedence list. These would be
adjacent rules where the conditions are mutually exclusive so, like,
we don't care what order those are checked in.)

Anyway, if you think about that structure, you realize that each
rule is set up as an exception to *the next rule*. In other words,
the rules could have been written

{R1:} When cond1: instead of R2, do code1.
{R2:} When cond2: instead of R3, do code2.
...

So the precedence problem is now recast as the rule-naming problem!
The code says "Instead of RULEBOOK", and the compiler is trying to
figure out (with the author's help) which rule in the rulebook is
being exceptionized.

...and having got to this clever conclusion, I realized that it didn't
do crap to help me actually solve the problem. Baking a linear-order
model into the language seems like a misstep, anyhow.

--Z

--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*
If the Bush administration hasn't subjected you to searches without a warrant,

it's for one reason: they don't feel like it. Not because you're innocent.

Adam Thornton

unread,
Sep 19, 2006, 8:52:58 PM9/19/06
to
In article <iYzPg.9638$cw.513@fed1read03>,
"Kevin Forchione" <ke...@lysseus.com> wrote:
(i.e. insteadOf(Eating(Apple), DropDead(Player)))

Oooh, nice demonstration of Turing-Completeness.

Adam

Adam Thornton

unread,
Sep 19, 2006, 8:56:17 PM9/19/06
to
In article <1158601961.6...@h48g2000cwc.googlegroups.com>,

steve....@gmail.com wrote:
> Rarely (if ever) do you want an object to
> change its overall strategy for dealing with the runtime situation, to
> become another class.

Is this true? Let's say that the actor Alan, in the game, DropsDead()
because Alan invoked the Eating method of the Apple object, and it was
poisoned.

In my (I7) WIP I deal with this by removing the Alan object (an NPC); in
its place I swap in a Dead_Alan object, which is a Thing.

This strikes me as inelegant. It would, I think, be prettier to change
its superclass from "Person" to "Corpse" or something like that. And I
don't think this is a terribly outr

Adam

Adam Thornton

unread,
Sep 19, 2006, 9:21:20 PM9/19/06
to
In article <adam-B10BD0.1...@fileserver.fsf.net>,
Adam Thornton <ad...@fsf.net> wrote:

Bugger.

Cmd-E when I meant to hit alt-E.

Trying again:

Is this true? Let's say that the actor Alan, in the game, DropsDead()
because Alan invoked the Eating method of the Apple object, and it was
poisoned.

In my (I7) WIP I deal with this by removing the Alan object (an NPC); in
its place I swap in a Dead_Alan object, which is a Thing.

This strikes me as inelegant. It would, I think, be prettier to change
its superclass from "Person" to "Corpse" or something like that. And I

don't think this is a terribly outré example.

Wouldn't changing the superclass be the right thing to do here?

Adam

Kevin Forchione

unread,
Sep 19, 2006, 10:27:46 PM9/19/06
to
"Adam Thornton" <ad...@fsf.net> wrote in message
news:adam-3C4E07.1...@fileserver.fsf.net...

I'm a bit reckless I suppose, but I don't necessarily see anything wrong
with that approach. I've used superclass changes in some of my projects. It
provides, for instance, and easy way to send a a parse string to a base
class, have the base class execute a parse method on the string until it
identifies that the string belongs to a derived class, change the base class
superclass to the derived class and repeat the parse method on the new
superclass. The advantage to this approach is that all state changes made
during the parsing are retained in the identity of the object.

Where things do begin to get a bit dodgy are when you replace *some* of the
superclasses of a multiple inheritance. In that case you run the risk of the
inheritance of methods breaking (just dropping off the inheritance tree or
having mismatched parameter lists). But I suspect that if you switched the
single inherited superclass of Person for Corpse you wouldn't suffer any
noticeable side-effects, barring the caveat below...

One thing to remember, of course, is that the methods of the original class
definition will be part of the object's definition. So if Bob defines
special methods to override Person behaviors, those methods will still be
part of Bob when he then inherits from Corpse. The same will be true of any
state variables directly defined by Bob, or that have changed between Bob's
initialization as a Person and Bob's initialization as a Corpse.

--Kevin


ChicagoDave

unread,
Sep 20, 2006, 12:37:12 AM9/20/06
to
> Kevin Forchione wrote:
> One thing to remember, of course, is that the methods of the original class
> definition will be part of the object's definition. So if Bob defines
> special methods to override Person behaviors, those methods will still be
> part of Bob when he then inherits from Corpse. The same will be true of any
> state variables directly defined by Bob, or that have changed between Bob's
> initialization as a Person and Bob's initialization as a Corpse.

Why wouldn't you add dead or alive to Person and add the corpse
behavior?

David C.

Example:

"Dead Or Alive" by David Cornelson

People can be alive or dead. People are usually alive.

Instead of examining a dead person:
say "It's just a corpse now.";
stop the action.

The Operating Room is a room. "This is a brightly lit room."

David is a man in the Operating Room. The description of David is
"Barely alive, but looks to be recovering."

Before attacking David:
say "You pull the plug and David dies.";
Now David is dead;
stop the action.

Test me with "x david / kill him / x him";

Kevin Forchione

unread,
Sep 20, 2006, 1:22:25 AM9/20/06
to
"ChicagoDave" <david.c...@gmail.com> wrote in message
news:1158727032....@m73g2000cwd.googlegroups.com...

>> Kevin Forchione wrote:
>> One thing to remember, of course, is that the methods of the original
>> class
>> definition will be part of the object's definition. So if Bob defines
>> special methods to override Person behaviors, those methods will still be
>> part of Bob when he then inherits from Corpse. The same will be true of
>> any
>> state variables directly defined by Bob, or that have changed between
>> Bob's
>> initialization as a Person and Bob's initialization as a Corpse.
>
> Why wouldn't you add dead or alive to Person and add the corpse
> behavior?

Lol! Of course there are many ways to model this. The chief reason I can see
for making such a separation would be to avoid contradictory behaviors in
complex object definitions. Say for example, a corpse that roams about the
house because its movement code didn't take the deadflag into consideration.

But another example would be a catepiller turning into a butterfly. In this
case there are distict behaviors for these two classes, though we can make
the argument that it may indeed be the same "self" in both cases.

Or perhaps you have a backpack that unfolds into a pup tent?

Of course all of these have been done before in other ways, but if
obj.setSuperclassList([Butterfly]) will do the trick, hmmm, then why not?

--Kevin


Krister Fundin

unread,
Sep 20, 2006, 8:26:26 AM9/20/06
to

"Kevin Forchione" <ke...@lysseus.com> skrev i meddelandet
news:xG1Qg.16$zf3.12@fed1read03...

>
> One thing to remember, of course, is that the methods of the original
> class definition will be part of the object's definition. So if Bob
> defines special methods to override Person behaviors, those methods will
> still be part of Bob when he then inherits from Corpse. The same will be
> true of any state variables directly defined by Bob, or that have changed
> between Bob's initialization as a Person and Bob's initialization as a
> Corpse.

I've found a pretty good coding pattern for these situations:

class BobCommon: object
// common properties here
;

class BobPerson: BobCommon, Person
// properties for the living Bob here
;

class BobCorpse: BobCommon, Thing
// properties for the dead Bob here
;

bob: BobPerson
// very few properties here; basically just the location
// and such
;

That leaves just a single superclass to worry about, and it's pretty
safe to switch back and forth. The only remaining problem is that
of initialization. In TADS 3, the dictionary will be unaffected by
the superclass change, for instance.

-- Krister Fundin

ChicagoDave

unread,
Sep 20, 2006, 10:35:41 AM9/20/06
to
> Kevin Forchione wrote:
> Lol! Of course there are many ways to model this. The chief reason I can see
> for making such a separation would be to avoid contradictory behaviors in
> complex object definitions. Say for example, a corpse that roams about the
> house because its movement code didn't take the deadflag into consideration.

A Person can be alive, dead, or undead.

> But another example would be a catepiller turning into a butterfly. In this
> case there are distict behaviors for these two classes, though we can make
> the argument that it may indeed be the same "self" in both cases.

I still see these as two behaviors of the same thing and would code it
as such.

> Or perhaps you have a backpack that unfolds into a pup tent?

It's just a special behavior for a special backpack.

Maybe it's just me, but I've never used the replace object with
different object technique. I've always added the new behavior to the
appropriate class. As for changing SuperClasses, that's beyond my
understanding of OO.

I can see that creating different objects would be convenient to some
degree, but all that SuperClass stuff gives me a headache and managing
behaviors doesn't.

David C.

Kevin Forchione

unread,
Sep 20, 2006, 12:09:53 PM9/20/06
to
"ChicagoDave" <david.c...@gmail.com> wrote in message
news:1158762941.8...@m73g2000cwd.googlegroups.com...

> I can see that creating different objects would be convenient to some
> degree, but all that SuperClass stuff gives me a headache and managing
> behaviors doesn't.

Lol! How can it? Since Inform doesn't support superclass replacement? But
yes, there are many ways to model these things. Probably a good thing.

--Kevin


Adam Thornton

unread,
Sep 20, 2006, 12:30:36 PM9/20/06
to
In article <1158762941.8...@m73g2000cwd.googlegroups.com>,
"ChicagoDave" <david.c...@gmail.com> wrote:

> A Person can be alive, dead, or undead.

Yeah, but then we have to manually define male and female and neuter
alive, dead, and undead persons.

> Maybe it's just me, but I've never used the replace object with
> different object technique. I've always added the new behavior to the
> appropriate class.

Yeah, but if you have two fairly complicated sets of behaviors, this
turns into a lot of work, because you're manually importing all the
default methods of the transformed-into object rather than just letting
the class system figure it out.

> As for changing SuperClasses, that's beyond my
> understanding of OO.

Think of it as just picking up an object and moving it somewhere else in
the tree. Anything you didn't already override is now inherited from
the new superclass.

> I can see that creating different objects would be convenient to some
> degree, but all that SuperClass stuff gives me a headache and managing
> behaviors doesn't.

Fair enough.

I find the easiest thing (in Inform) is to swap in a different object
with the same tokens used by the player to represent it. I also think
that's totally gross, though.

Adam

Kevin Forchione

unread,
Sep 20, 2006, 12:42:05 PM9/20/06
to
"Adam Thornton" <ad...@fsf.net> wrote in message
news:adam-DEF7CE.0...@fileserver.fsf.net...

> In article <1158762941.8...@m73g2000cwd.googlegroups.com>,
> "ChicagoDave" <david.c...@gmail.com> wrote:
>> As for changing SuperClasses, that's beyond my
>> understanding of OO.
>
> Think of it as just picking up an object and moving it somewhere else in
> the tree. Anything you didn't already override is now inherited from
> the new superclass.

Another way to think of it is as an entity, a "self" from which you are
dynamically adding and removing subsets of states and behaviors to the total
set of its being.

--Kevin


Reply all
Reply to author
Forward
0 new messages