Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

TADS3 abstract things

15 views
Skip to first unread message

Rick Hawk

unread,
Dec 18, 2008, 1:21:15 AM12/18/08
to
The many manuals for TADS 3 will tell you how to do a lot of things, but
sometimes it feels like they always intentionally avoid explaining
whatever I want to do.

For example, I might want to represent something abstract as a thing
that the parser can recognize. Suppose that there is a stack of junk in
the room and I want to 'examine the top of the pile'. There is no thing
in the room called 'the top of the pile' in the conventional sense. It's
not the pile itself, because that would have an entirely different
descriptions.

Maybe the pile has a lawnmower, a VCR, and a shoebox on the top. I want
'open the top of the pile' to be the same as 'open the shoebox', but I
don't want to put the required vocabulary into the shoebox, since the
shoebox isn't always going to be on top of the pile. I could put a
month-old pizza there, and it woulc completely change the meaning of
'the top of the pile'.

So I want a thing whose meaning can change, making it abstract. I want
it to be resolved from a noun phrase much like any other noun phrase,
except that somewhere between parsing and verifying the action, the
abstract thing should be replaced by a concrete thing. On top of that,
if it's not too much trouble, I'd like the abstract thing to be able to
inherit vocabulary from the concrete thing it refers to. So if the top
of the pile were stinky, then I should be able to 'kill the stinky top
of the pile'.

I've read all the manuals and I've browsed the library source files
quite a bit. The manuals barely break the surface of how the parser
works on the inside, so when I try to do something tricky like this I
feel that I'm on my own.

The brute-force way to do this seems to be by editing the dictionary,
but that seems awfully prone to problems. I have also considered that
remapping might be helpful, but it doesn't have the vocabulary
inheritence feature that I want and it doesn't really seem to be
intended for this purpose.

Another option which I consider promising is to create a new grammar
rule for simpleNounPhrase, something like:
grammar simpleNounPhrase(abstract): abstractNounPhrase->anp_
: NounPhraseWithVocab ...;
And then I define abstractNounPhrase to be exactly like simpleNounPhrase
is now. The difference is that simpleNounPhrase(abstract) has a
definition for getVocabMatchList that uses an entirely different scope
than the one given to it. This will be the scope of abstract concepts
and this new scope will allow my new rule to succeed where all others
fail because abstract concepts will not in any normal scope.

So my new getVocabMatchList definition can find things that will never
be found any other way, but it won't return those things. Instead, it
will return the concrete things that the abstract things represent. And
because abstractNounPhrase is an alternative for simpleNounPhrase, the
player will be allowed to use abstractNounPhrase wherever a
simpleNounPhrase is expected, including following an adjective. This
allows the top of the pile to be stinky if it has that nature.

Maybe I've got this all figured out, but I would be foolish to claim
that I fully understand the TADS 3 parser. It deserves a very thick
manual entirely devoted to its intricacies for people who feel like
doing this sort of thing. So I'm asking if my strategy will work as I
intend. Is there some subtlety to the parser that will cause it break
when I do this? If so, what is the best way to fix it? What should I
know that I might be missing?

One more thing, about a different sort of abstract thing. I also want to
be able to define a decorative thing that I can use many times as
separate instances, but have it be fully functional in each instance.
For example, you often see vending machines in every hallway of some
buildings. So I want to be able to say:
vm42: VendingMachine;
And there's a vending machine. The class 'VendingMachine' should take
care of all the details with appropriate defaults. This can very easily
be done in a limited way by making VendingMachine a subclass of Thing
and filling in the desc and action handling properties appropriately,
but that is far from a fully functioning vending machine.

Vending machines have contents and you cannot inherit contents from a
class, but I want every vending machine to be fully stocked with items
that can be examined and maybe even have other verbs used upon them just
like any other thing.

I know that I can write a PreinitObject to automatically stock my
vending machines. The question is, should I stock them with dynamically
created objects, or should I stock them with shared objects? I wish
there were a way to have a PreinitObject generate static objects because
I know that they are less expensive than dynamic objects. Each dynamic
object requires more memory and makes the garbage collector slower
because it has more to search.

Is it okay to casually fill my game with dozens of dynamic objects that
are generated automatically from Preinit code? I'm not sure, but I don't
think so, so I looked for alternatives.

Shared objects are much better than dynamic objects in one way: they use
fewer resources. On the other hand, they have no 'location' property
like an ordinary thing would, since shared objects are in the contents
list of many things. This leads to a couple of problems.

First, they cannot access their location object for customizing
messages. For example, I might want to vary the look of the control
panel of a vending machine like this:
vm56: VendingMachine controlsDesc = "It has big, round buttons.";

Then when the player says 'examine controls' the control panel part of
the vending machine would look at the controlsDesc of its vending
machine to output the custom message instead of the default one. I can't
do that without a 'location' property.

The other problem is that if there are two vending machines in the same
room, there's never going to be any sort of ambiguity between the
contents of one and the contents of the other. Suppose it matters
whether you examine the chocolate bar of vending machine A or the
chocolate bar of vending machine B. Since both chocolate bars are
actually the same object, TADS is never going to ask for which one you
meant, even if you would get a different response from examining one
rather than the other.

So now I am again looking at modifying the parser, this time to
accomodate these shared things more fully. I'm making a
VendingMachinePart class and imagining a parser that will notice
VendingMachineParts and react by searching the scope for
VendingMachines. If there is more than one VendingMachine then it will
dynamically create a copy of that part for each of them, with
'location' properly defined, ready for disambiguation.

I hope you can imagine how nice it would be to be able to create
decorative vending machines that are fully implemented and customized
with a little bit of flavor, but with nearly no effort or wasted
resources. And of course, this could be applied to dozens of different
kinds of objects other than vending machines. Chairs have legs; cabinets
have doors; doors have knobs; all these things which would be far too
tedious for an author to implement could be handled automatically.

I have no idea how to make it happen.

Captain Mikee

unread,
Dec 18, 2008, 11:41:55 AM12/18/08
to
On Dec 18, 1:21 am, Rick Hawk <n...@e.mail> wrote:
> Suppose that there is a stack of junk in
> the room and I want to 'examine the top of the pile'. There is no thing
> in the room called 'the top of the pile' in the conventional sense.

> One more thing, about a different sort of abstract thing. I also want to


> be able to define a decorative thing that I can use many times as
> separate instances, but have it be fully functional in each instance.
> For example, you often see vending machines in every hallway of some
> buildings.

I apologize for not having any coding advice; I don't know TADS at
all. But both of these problems look like they could be made much
simpler by thinking more about what your game really needs to achieve.
It's easy to get bogged down in realism, but if your game only allows
the player to do things that make sense in the story, you can
eliminate a lot of difficult-to-implement alternatives.

For example, if you have things in a pile, you need to keep track of
what's on top, but you might not need to refer to the top explicitly.
When you "examine pile," the response could tell you what's on top,
and then you could refer to that thing specifically. If you try to do
something to an object not on top of the pile, you can have a "you
can't do that, it's covered by other things" response. Then the player
never has to mention the top of the pile separately.

For the vending machine, the solution really depends on the story. How
many candy bars would a player really want to have? Don't create any
more than that; if the player tries to take more, come up with a
reasonable response that suggests they have already taken as many as
they need... or come up with a polite way of having one of them
disappear. If you really need a large number of candy bars, maybe you
can make a "collection of candy bars" object that has a count
property. Don't let the player divide the collection other than to do
something with a single candy bar. I don't know how class hierarchies
work in TADS, but it ought to be possible to have each vending machine
inherit some properties from a Vending Machine "template" and then
create some of its own - what type of object it dispenses, unique
descriptions for the controls, etc. Use the old Infocom trick of
giving each similar object a unique description - wooden door, stone
door, round button, blue button, etc...

Jim Aikin

unread,
Dec 18, 2008, 11:54:03 AM12/18/08
to
Captain Mikee wrote:
>
> I apologize for not having any coding advice; I don't know TADS at
> all. But both of these problems look like they could be made much
> simpler by thinking more about what your game really needs to achieve.
> It's easy to get bogged down in realism, but if your game only allows
> the player to do things that make sense in the story, you can
> eliminate a lot of difficult-to-implement alternatives.

I second that advice. I've written three games in TADS 3, but I wouldn't
know how to tackle the challenges you're posing for yourself. The first
time I tried to learn T3 I got hung up and stopped (went back to I6)
because I was trying to implement a window that the player could look
through and see what's in the other location. This is one of those
snarly simulation challenges -- and it wasn't necessary for my game at
all. I was just being obsessive about realism.

> I don't know how class hierarchies
> work in TADS, but it ought to be possible to have each vending machine
> inherit some properties from a Vending Machine "template" and then
> create some of its own - what type of object it dispenses, unique
> descriptions for the controls, etc.

It's dead easy. You just make instances of your VendingMachine class and
then give them whatever properties you like. The object's properties,
wherever they exist, silently override the class properties -- but you
can also use the inherited keyword in your own code to refer back to the
code in the class.

--JA

Rick Hawk

unread,
Dec 18, 2008, 2:26:09 PM12/18/08
to
In article <gidv7f$u15$1...@news.motzarella.org>, Jim Aikin wrote:
> Captain Mikee wrote:
> >
> > I apologize for not having any coding advice; I don't know TADS at
> > all. But both of these problems look like they could be made much
> > simpler by thinking more about what your game really needs to achieve.
> > It's easy to get bogged down in realism, but if your game only allows
> > the player to do things that make sense in the story, you can
> > eliminate a lot of difficult-to-implement alternatives.
>
> I second that advice. I've written three games in TADS 3, but I wouldn't
> know how to tackle the challenges you're posing for yourself. The first
> time I tried to learn T3 I got hung up and stopped (went back to I6)
> because I was trying to implement a window that the player could look
> through and see what's in the other location. This is one of those
> snarly simulation challenges -- and it wasn't necessary for my game at
> all. I was just being obsessive about realism.

What was the challenge that stopped you from making that window? It
sounds directly straightforward to me! TADS 3 comes with LookThrough
already defined as a verb and all you have to do is write yourself a
dobjFor(LookThough) { action() {...} } in your window and you can have
it display anything you want.

Now that I do a little research on this issue, I see that there is even
a Thing.lookAroundPov mathod that is specifically designed for
displaying how something appears to an actor through a POV that's not
the actor, like the other side of a window.

I suppose you wanted to be able to examine things through the window,
too. I've never actually tried that, but I'm pretty sure that the
library allows for that using the SenseConnector class which allows two
otherwise separate places to become one as far as senses are concerned.
I know from the manuals that it allows you to talk to NPCs in far-off
places, so I expect it would work for examine, too.

Back to your point about only implementing things which are really
necessary, I admit that the second part of my question was just a
fishing expedition for something awesome that you guys might help me
with, even though I didn't really need it. It was only meant for
decoration. On the other hand, the bit about having an abstract thing
that the parser recognizes as different concrete things at different
times is really something that I definitely need. My game wouldn't be at
all the same without it.

Plus, I really don't think that "it was too difficult to implement" is
an excuse that players have sympathy for when they are deciding whether
they like a game.

Eric Eve

unread,
Dec 18, 2008, 3:38:30 PM12/18/08
to
"Rick Hawk" <n...@e.mail> wrote in message
news:MPG.23b4435d8...@shawnews.vc.shawcable.net...

Maybe you want to think about this in a different way. Instead of
having an abstract thing that represents the top of the pile, you
could have arrange it so that particular concrete things can be
referred to as 'top of the pile' when they're in their top of the
pile state.

First define two ThingStates:

topOfPileState: ThingState
stateTokens = ['top', 'pile']
;

notTopOfPileState: ThingState
;

Then define a PileItem mix-in class:

class PileItem: object
vocabWords = 'top/pile'
allStates = [topOfPileState, notTopOfPileState]
getState = notTopOfPileState
;

Then use this mix-in class with anything that might be moved to the
top of the pile, e.g.:

shoebox: PileItem, OpenableContainer 'stinky old shoebox' 'old
shoebox'
;

When the shoebox is at the top of the pile, change shoebox.getState
to topOfPileState and it should respond to the vocabulary 'top of
pile', 'stinky top of pile' and so forth. All commands directed to
'the top of the pile' will automatically be directed to the object
that's in the topOfPileState.

Caveat - I've not tested this so it may need tweaking, but it should
point you in the right direction.

-- Eric

Jim Aikin

unread,
Dec 18, 2008, 3:47:27 PM12/18/08
to
Rick Hawk wrote:
>
> What was the challenge that stopped you from making that window? It
> sounds directly straightforward to me! TADS 3 comes with LookThrough
> already defined as a verb and all you have to do is write yourself a
> dobjFor(LookThough) { action() {...} } in your window and you can have
> it display anything you want.

True. Bear in mind, this was at a very early stage in my learning T3.
But the thing is, there might be a bookcase that's on the same wall as
the window, in which case its contents shouldn't be visible through the
window. And in theory, the player could put anything on the bookcase. So
you need to know not just what's in the room but what's _visible_ in the
room. It can get messy.

When I first tried going through the Heidi game, the window caused the
stuff in the interior of the hut to be displayed in the room description
when you were OUTSIDE the hut. That was what got me thinking about it.
And I didn't know how to fix it, because I didn't know a darn thing yet.

DistanceConnectors and SenseConnectors can do more specific things --
but I hadn't yet discovered those.

> On the other hand, the bit about having an abstract thing
> that the parser recognizes as different concrete things at different
> times is really something that I definitely need. My game wouldn't be at
> all the same without it.

Look up dobjFor(Default) and dobjFor(All) in "Learning T3". dobjFor(All)
might be the right tool for the job, because your code could identify
the action and then start a new embedded action that was redirected
toward the object that is currently on the top of the stack.

The other thing you might want to know about is cmdDict.addWord. This
method is not listed in the Library Reference Manual, as far as I can
see, but it's in chapter 10.2.2 of Learning T3. Using this and
cmdDict.removeWord, you can add and subtract vocabulary from your
abstract "top of the stack" object as needed.

> Plus, I really don't think that "it was too difficult to implement" is
> an excuse that players have sympathy for when they are deciding whether
> they like a game.

Up to a point, that's certainly true. I think players have a set of
expectations (a moving target -- may change from year to year) that
authors need to be aware of. The author who bails on any of these
standard facets of implementation can expect little sympathy. On the
other hand, if nobody has ever done it before, players won't expect to
see it, so if you don't implement it but rather deploy a simpler
workaround, they probably won't even notice.

--JA

Jim Aikin

unread,
Dec 18, 2008, 3:51:39 PM12/18/08
to
As usual, Eric's solution is _much_ more elegant than mine!

--JA

Rick Hawk

unread,
Dec 18, 2008, 6:00:15 PM12/18/08
to
In article <giecc6$2hu$1...@frank-exchange-of-views.oucs.ox.ac.uk>, Eric
Eve wrote:
> First define two ThingStates:
>
> topOfPileState: ThingState
> stateTokens = ['top', 'pile']
> ;
>
> notTopOfPileState: ThingState
> ;
>
> Then define a PileItem mix-in class:
>
> class PileItem: object
> vocabWords = 'top/pile'
> allStates = [topOfPileState, notTopOfPileState]
> getState = notTopOfPileState
> ;

I'm shocked. I really thought I'd looked at this problem from every
possible angle, but somehow I missed something so nearly ideal. I must
have been blinded by the conventional usage for ThingState for lighting
torches so it never occurred to me to look at using it in such a devious
way.

I don't think it's completely ideal because I'm pretty sure that
ThingState was never intended to be used for this, but you've opened up
a whole new approach to this problem. I would probably never have
thought of putting the abstract vocabulary in every object and then
having those objects remove themselves from the resolution lists when
the abstract terms did not apply.

Now that I see this way of doing it, I'm certain that I can come up with
something that works, thanks to you.

Eric Eve

unread,
Dec 19, 2008, 2:55:09 AM12/19/08
to

"Rick Hawk" <n...@e.mail> wrote in message
news:MPG.23b4759fc...@shawnews.vc.shawcable.net...

> In article <giecc6$2hu$1...@frank-exchange-of-views.oucs.ox.ac.uk>,
> Eric
>
> I'm shocked. I really thought I'd looked at this problem from
> every
> possible angle, but somehow I missed something so nearly ideal. I
> must
> have been blinded by the conventional usage for ThingState for
> lighting
> torches so it never occurred to me to look at using it in such a
> devious
> way.
>
> I don't think it's completely ideal because I'm pretty sure that
> ThingState was never intended to be used for this,

But if ThingStates can do the job here, why are they less than
ideal? They are probably the neatest way of making vocabulary apply
or not apply to an object depending on the object's state, and
that's what you need here. The fact that ThingState wasn't conceived
with this particular application in mind is neither here nor there,
is it?

-- Eric

Rick Hawk

unread,
Dec 19, 2008, 3:26:37 PM12/19/08
to
In article <gifk0u$fnk$1...@frank-exchange-of-views.oucs.ox.ac.uk>, Eric
Eve wrote:
> But if ThingStates can do the job here, why are they less than
> ideal? They are probably the neatest way of making vocabulary apply
> or not apply to an object depending on the object's state, and
> that's what you need here. The fact that ThingState wasn't conceived
> with this particular application in mind is neither here nor there,
> is it?

Well, ThingStates certainly get the job done and I did say it was a
nearly ideal solution, but since you ask, there is one small problem.
It's not going to be an issue for me, but someone might want to make a
game where you could put a top hat on the pile. Unfortunately, with your
solution the player wouldn't be able to refer to the hat as a 'top hat'
unless it were on top of the pile, even though it is still top no matter
where it is, because top is a description of style, not of location.

As for my other problem, I am beginning to think that I was too quick to
discard the idea of automatically generating dynamically created objects
to fill in the parts of my things. I'm not really sure how expensive it
is to build and maintain a dynamically created object, so going to
enormous lengths to understand and manipulate the parser just to avoid
them might be a waste.

But then again, Learning TADS 3 says "In principle the player could
go on picking apples forever; in practice the game will probably start
grinding to a halt after a few dozen apples have been picked." So I
thought, "Uh oh, I've only got a few dozen dynamically created objects
to play around with, so I'd better not waste them!" But now I realize
that it is really hard to get the parser to generate dynamic objects as
it resolves nouns, so I decided to test the limits of dynamic objects.

I recreated that infinite apple tree from Learning TADS 3 and tried
picking several dozen apples. I actually picked about 300. And as a
result I did notice some slowing of the game. Yet I don't know if that
was because I had 300 dynamically created objects or just because I had
300 objects all in the same room. I don't know how many more it would
have taken to grind things to a halt.

Does anyone know how much a dynamically created object really costs to
the VM? How much effort should I make to avoid them when they aren't
absolutely necessary?

steve....@gmail.com

unread,
Dec 21, 2008, 4:42:11 PM12/21/08
to
Rick Hawk wrote:
> Yet I don't know if that
> was because I had 300 dynamically created objects or just because I had
> 300 objects all in the same room.

The thing that slowed you down was scope calculation stuff, among
other things. Hundreds of object in scope is going to slow you down.
Thousands of objects out of scope will also slow you down (because
even out-of-scope objects are queried each turn).

The memory overhead for maintaining hundreds of objects (dynamic or
otherwise) is *never* going to be a practical problem, if only because
the computation problem is going to become massive long before memory
becomes an issue.

> How much effort should I make to avoid [dynamically created objects]


> when they aren't absolutely necessary?

You'll be fine so long as you avoid having hundreds of objects in
scope or thousands of objects in the game. BTW, dynamically created
objects are equal to static objects in all but name.

Rick Hawk

unread,
Dec 21, 2008, 6:39:16 PM12/21/08
to
In article <4fd36fb7-faa2-498b-a7a3-

ddff59...@e25g2000vbe.googlegroups.com>, Steve Breslin wrote:
> You'll be fine so long as you avoid having hundreds of objects in
> scope or thousands of objects in the game. BTW, dynamically created
> objects are equal to static objects in all but name.

That can't be true. I'm sure I read somewhere that dynamically created
objects are more expensive. Eric Eve said that a few dozen dynamic
objects would grind a game to a halt. And on top of that, every dynamic
object requires resources from the garbage collector. The garbage
collector needs some sort of data structure to iterate through the
dynamic objects and it would surely take longer to do garbage collection
with many dynamic objects.

Maybe someday a new version of 'new' will be added to TADS for
dynamically creating static objects. Until then, I'll just hope that
you're right that dynamic objects aren't much worse than static objects.
I remember reading somewhere that in TADS 2 dynamic objects were
terrible.

Every day I'm grateful for TADS so at least I don't have to use Inform
with its tight resource limits and 9-letter words. I've read too many
horror stories on this group to ever even give Inform a try, despite how
cute Inform 7 looks.

steve....@gmail.com

unread,
Dec 21, 2008, 6:55:27 PM12/21/08
to
Rick Hawk wrote:
> That can't be true. I'm sure I read somewhere that dynamically created
> objects are more expensive. Eric Eve said that a few dozen dynamic
> objects would grind a game to a halt.

Well, Eric was incorrect if he emphasized/distinguished dynamic
objects, or maybe you mistook the point of emphasis. No big deal
either way. :)

But definitely he couldn't have been talking about memory stuff, but
library-side calculations (scope calculation and such). "A few dozen"
is probably a good approximation of when per-turn processing lagtime
becomes visible, if you have an old computer.

It really doesn't matter whether an object is dynamic or static: they
work precisely the same way. (Yes, in terms of garbage collection
also: the garbage collector does iterate static objects.) The only
difference is that dynamic objects cannot be referenced by a
programmatic name. Static objects can be anonymous also. Really no
difference! :)

eric...@hmc.ox.ac.uk

unread,
Dec 22, 2008, 3:55:35 PM12/22/08
to

Well, I've certainly found code creating dynamic objects cause a
massive slowdown in the past (for whatever reason), though I can't
reproduce that now. So either there was something odd going on my
code, or TADS 3 has changed in this respect since I observed this
effect (quite possible since it was quite a while back) or, as Steve
suggests, it was due to side-effects such as scope calculation on a
slower machine than the one I'm using right now.

The code I *may* have had in mind was the code to dynamically create
rooms in the Dynamic Locations section of the Tour Guide. But I see
that code allows the dynamic creation of up to 50 rooms, so even then
I must have regarded "a few dozen" dynamically created rooms as a low
estimate of what might prove problematic.

Well, I just tried another test. Code that dynamically creates over
700 identical pebbles, one per turn, does not slow the game down each
turn a pebble is created in itself; but it does make commands like X
PEBBLES run very slowly indeed, and TAKE A PEBBLE is pretty slow. The
point is probably not that the pebbles are dynamically created per se,
but that one is more likely to get a large number of objects like this
by dynamic creation.

So, it may what I had in mind was the code to dynamically create
candles in the Dispenser section of the Tour Guide. Testing this on
the machine I'm currently using with an increased value of the
maxCandlesToCreate variable starts to show a lag after taking about
100 candles, a delay that becomes very noticeable by the time about
150 candles have been taken. Again the delay is not because dynamic
objects are more expensive but, I imagine, because the parser is
having to run the verify() routine on 150 candles to work out which
one should be taken (each time a candle is taken from its Dispenser, a
new one is created in the Dispenser).

Thus, the reason that creating dynamic objects is likely to cause a
slow-down is not because dynamic objects are inherently expensive but
because creating a large number of dynamic objects is more likely to
result in the presence of a large number of similar objects the
library may then need to operate on, as Steve suggests.

-- Eric

steve....@gmail.com

unread,
Dec 22, 2008, 4:15:28 PM12/22/08
to
Eric Eve wrote:

> I've certainly found code creating dynamic objects cause a

> massive slowdown in the past[.]

I'm sure that's true, and it's trivially easy to reproduce no matter
the machine. But that's "in-game" (Thing/simulation) objects. At any
given moment, as you'll recall, there's thousands of programmatic
objects in memory, causing no harm at all. The slowdown comes from
scope calculation and other library-side processes.

> [T]he delay is not because dynamic


> objects are more expensive but, I imagine, because the parser is
> having to run the verify() routine on 150 candles to work out which
> one should be taken (each time a candle is taken from its Dispenser, a
> new one is created in the Dispenser).

That's one part, or creating many same-name static objects will have
the same effect. I would guess that verification lag is less severe
than the scope lag; in either case, the dynamic origin of the object
is entirely irrelevant.

I think the assumption might have been that you don't get huge numbers
of objects unless you have dynamic objects (from dispensers, etc.).
Somebody picked up the idea, didn't consider the assumption, and drew
a false conclusion that dynamic objects were hazardous.

Rick Hawk

unread,
Dec 22, 2008, 4:20:22 PM12/22/08
to
In article <eeb92faf-6f8e-4dd1-b503-

dc3445...@i20g2000prf.googlegroups.com>, Eric Eve wrote:
> Thus, the reason that creating dynamic objects is likely to cause a
> slow-down is not because dynamic objects are inherently expensive but
> because creating a large number of dynamic objects is more likely to
> result in the presence of a large number of similar objects the
> library may then need to operate on, as Steve suggests.

That is very good to know! I certainly see now that my earlier efforts
to avoid dynamic objects and to do object-sharing were useless. Using
object sharing in place of dynamic objects is not helpful since object
sharing cannot reduce the number of objects in scope, so noun resolution
would still be just as difficult.

It's now clear why MultiInstance works the way it does.

Mike Roberts

unread,
Dec 22, 2008, 6:33:57 PM12/22/08
to
<eric...@hmc.ox.ac.uk> wrote:
> Well, I've certainly found code creating dynamic objects cause a
> massive slowdown in the past (for whatever reason), though I can't
> reproduce that now. So either there was something odd going on my
> code, or TADS 3 has changed in this respect since I observed this
> effect (quite possible since it was quite a while back) or, as Steve
> suggests, it was due to side-effects such as scope calculation on a
> slower machine than the one I'm using right now.

Creating objects with 'new' is actually very cheap. It always has been,
because something I learned from tads 2 was that a slow 'new' is hard to
live with. Tads 2's 'new' is fairly heavy-weight, as a result of having
been retrofitted into that VM fairly late in the game. In OO programming
(in general - not just IF), you really have to be able to use 'new' with
abandon, so it got to be a significant restriction in tads 2 that you had to
be careful not to overdo the 'new's. Among other things, it made it hard to
move the parser from the interpreter into the byte code. So one of the key
motivations (and thus a key design goal) for a new VM was to make 'new'
cheap.

To give you a concrete idea, about 2500 objects are 'new'ed in the course of
a typical >LOOK, and about 16000 in the course of something like >X ALL in
the library sample game. These are mostly miscellaneous bookkeeping objects
that the parser and execution planner create, and they're basically all
ephemeral.

> Well, I just tried another test. Code that dynamically creates over
> 700 identical pebbles, one per turn, does not slow the game down each
> turn a pebble is created in itself; but it does make commands like X
> PEBBLES run very slowly indeed, and TAKE A PEBBLE is pretty slow.
> The point is probably not that the pebbles are dynamically created per se,
> but that one is more likely to get a large number of objects like this
> by dynamic creation.

Exactly right. It's cheap to create objects with 'new', but what's not so
cheap is having tons of game-world objects sitting around. That's not
because 'new'ing them is expensive; it's mostly because the scope-checking
work is expensive. The cost of static and dynamic objects in this context
is identical - the dynamic/static status is pretty much irrelevant to the
run-time cost. If you created 700 identical static pebbles you'd get the
same results. The scope checking scales roughly as the square of the
in-scope object count, as I recall, so once you get past a certain threshold
it starts getting really ponderous as you add objects.

Note that the scope code was much more sensitive to the object count in
early versions, so your early experiences might have given you an intuitive
sense that it's best to keep object counts to a bare minimum. Somewhere in
the early beta stages I started seeing annoying response times on slower
machines with moderately complex rooms, so I spent a lot of effort
optimizing the scope code to speed things up. I got it to the point where
the response time stays decent even at the higher end of what games might
actually use in practice - say, around 100 objects in scope at one time. So
you shouldn't have to be *too* careful about minimizing in-scope objects as
long as you're staying within the standard sort of IF world model. If
you're thinking in terms of some big paradigm shift in the world model, like
creating a separate object for each grain of sand on a beach, that's another
matter.

--Mike Roberts
mjr underscore at hotmail dot com


** Posted from http://www.teranews.com **

0 new messages