I’ve run into a bad problem involving an interplay between either the Dynamic Tables or Dynamic Objects extensions for Inform 7 and user-defined relations. Basically the problem is that if a sufficient number of objects exist in the game world, and a relation could possibly hold between them (even though said relation does not in fact hold), then Inform 7 crashes when a new object is dynamically created using the Dynamic Objects extension. Whether the trouble is with Dynamic Objects, or rather with Dynamic Tables (which is required to run the former), or rather with my own code, I can’t say (the extensions themselves are both written in Inform 6 code, which I am not really able to comprehend). There was no contact info for the author of the extensions in the accompanying documentation, and my preliminary on-line research didn’t turn up any discussion of this issue anywhere. I was hoping that someone here might be familiar with the extensions and how Inform 7 allocates or uses memory.
I only recently started using the Dynamic Objects/Tables extension to solve a few problems in a sub-project that is part of a larger ruleset I’ve been working on. Everything was working fine until I integrated the sub-project into my main project, and immediately Inform 7 began to crash each time something was created per the Dynamic Objects process. After some experimenting, I discovered that a potentially large but in practice hardly-used relation defined in my main project was not getting along with either Dynamic Objects or Dynamic Tables. However, I don’t understand enough about how Inform 7 uses memory to really comprehend the true nature of the problem, except to say that the problem definitely seems to be some sort of memory issue.
In my main project, I have several actions where a new object is dynamically created. The process seems to finish, and report rules associated with it appear in the test game; then a very large number of error messages that say:
[** Programming error: tried to read outside memory using → **]
start running down the screen and Inform crashes (a true crash, i.e. “Inform 7 caused a stack fault in module Inform7.exe”). For example, I have an action where the player pours some water from a full cup into an empty cup, requiring the creation of a new bit of water in the empty cup. So in my test game, I see:
pour pitcher in mug
You pour some water from the pitcher into the mug.
[** Programming error: tried to read outside memory using → ]
[ Programming error: tried to read outside memory using → ]
[ Programming error: tried to read outside memory using → **]
repeated a few dozen times, after which Inform crashes.
I set out to see if I could construct a small test scenario that would recreate the problem, which is shown below. I’m not looking for any particular tips or advice on the substance of the rather crude code posted below, since it’s only purpose is to simply demonstrate the issue that crashes Inform for me; what I really need help with is determining the cause and hopefully potential solutions to the more general crashing scenario.
First I wrote a quick scenario that would utilize creating objects dynamically. Note that if anyone would like to try this scenario for themselves they’ll need both the Dynamic Tables and Dynamic Objects extensions available from the Inform 7 website, and will have to set the project file to compile to Glulx. Furthermore, hopefully as a new person to the forum here I can be excused for not yet getting the hang of the “code-posting” function, as the tabs in the following code were converted to spaces (so you’ll have to set the tabs manually in Inform).
[code]Include Dynamic Objects by Jesse Mcgrew.
Use slow route-finding.
Rule for printing room description details: stop.
Rule for printing room description details of a container: omit contents in listing.
The testarea is a room. The description of the testarea is “A bare room that serves as your workshop.”.
A tissue is a kind of thing. The description of a tissue is usually “A [if the noun is clean]pristine[otherwise]used[end if] white paper tissue with a hint of a pleasant fragrance.”. A tissue can be clean or soiled. A tissue is usually clean.
A container called a box of tissues is in the testarea. The description of the box of tissues is “A shoebox-sized box of tissues emblazoned with a bright blue and white pattern. [if the box contains anything]A tissue is sticking out of the top of the box[otherwise]The box is empty[end if].”. The box of tissues is open and not openable. The box of tissues has a number called tissuecount. Tissuecount is usually 25.
One tissue is in the box of tissues.
After printing the name of the box of tissues while taking inventory: omit contents in listing.
A pencil is in the testarea. The description of the pencil is “A sharpened No.2 pencil, painted a dull yellow. A fine eraser is on one end.”.
An eraser is a kind of thing. The description of an eraser is usually “A rubber eraser, with plenty of life left in it.”.
One eraser is part of the pencil.
A container called the trash can is in the testarea. The description of the trash can is “A small brown plastic trash bin.”. The trash can is open and not openable.
Check inserting something into the box of tissues:
if the second noun contains a tissue and the noun is not a tissue:
say “The box is only for tissues.” instead;
if the noun is a tissue:
if the noun is soiled:
say “Your wife will be very upset if you do that. Use the trash can, you slob.” instead.
Does the player mean taking a tissue that is in the box of tissues: it is likely.
Instead of taking a tissue:
if the noun is in the box of tissues:
if the tissuecount of the box of tissues is less than 1:
say “There aren’t any more tissues. Looks like you’ll have to wipe your nose on your sleeve.”;
stop the action;
otherwise:
if the tissuecount of the box of tissues is at least 2:
let newtissue be a new object cloned from the noun;
move newtissue to the player;
decrease the tissuecount of the box of tissues by 1;
say “You pull a tissue from the box.”;
otherwise:
let abcd be a random tissue in the box of tissues;
now abcd is carried by the player;
decrease the tissuecount of the box of tissues by 1;
say “You take the last tissue from the box.”;
otherwise:
continue the action.
Connexion relates things to each other.
The verb to phylink (he phylinks, they phylink, he phylinked, it is phylinked, he is phylinking) implies the connexion relation.
Definition: a thing is linkedup if it phylinks anything.[/code]
I had determined that a relation called “connexion” in my main project, which is in practice rarely used (it is used to simulate the flow of electricity between power outlets, power cords, and electrical devices) was somehow directly related to Inform crashing during/after dynamically creating an object, which is why I tacked the seemingly out-of-place definition of the relation onto the end of the tissue-test case presented here. I was initially a bit frustrated when I ran the tissue-test scenario presented here and there were no problems.
get tissue
You pull a tissue from the box.
After playing around for a while, I noticed that in the Index pane of my main project, the connexion relation is shown as requiring 19K of memory, but in the Index pane of this test scenario it was not even listed as having a memory usage. I had a thought then that perhaps the number of objects in my main project which could potentially participate in the connexion relation (even though in practice only a handful of items do so) might have some bearing on the problem. So I started adding on to the end of the tissue-test scenario presented above:
[code]A marble is a kind of thing. The description of a marble is usually “A shiny marble.”.
The northern-testarea is north of the testarea.
There are 50 marbles in the northern-testarea.
The southern-testarea is south of the testarea.
There are 50 marbles in the southern-testarea.
The western-testarea is west of the testarea.
There are 50 marbles in the western-testarea.
The eastern-testarea is east of the testarea.
There are 50 marbles in the eastern-testarea.[/code]
At this point, I was rewarded with the crashing problem faithfully recreated:
get tissue
You pull a tissue from the box.
[** Programming error: tried to read outside memory using → ]
[ Programming error: tried to read outside memory using → ]
[ Programming error: tried to read outside memory using → **]
repeated a few dozen times, after which Inform crashed.
I’m hoping someone will be able to offer some guidance about what may be happening here. What is outside memory, what is trying to read it (or perhaps–read ‘outside’ of it), and what is said reader “using”?
If need be I can find some other way to duplicate the effect of the “connexion” relation in my main project without using any relations at all, and I am now firmly committed to the requirement of being able to create objects dynamically. However, neither of these considerations really address the larger issues here, namely:
a) I am doing something wrong in using any sort of relation modeled in the format of the connexion relation, or
b) is there a bug or other problem in either the Dynamic Tables or Dynamic Objects extensions themselves (and if so, whether anything can be done about it), or
c) all of the above.
Thanks in advance to anyone able to comment on this admittedly obscure issue.