[I7] Writing External Files with "Safe" Data

I’m reading the section “Writing and reading tables to external files” in the manual and it says:

The only tables which Inform allows us to write into files are those containing “safe” data: numbers, units, times of day and kinds of value with named alternatives. Scenes, rules or rulebooks, in particular, are not allowed.

I’m attempting to write a table that would have this structure:

Table of Temporal Flow
agent      action     location     time stamp
person     waiting    room         9:00 AM
with 25 blank rows.

That seems to cause Inform to explode with a run time error when the table is written to.

The logic that writes to the table does the following:

if the number of blank rows in the Table of Temporal Flow is greater than zero:
	choose a blank row in the Table of Temporal Flow;
	now the agent entry is the actor;
	now the action entry is the current action;
	now the location entry is the location of the player;
	now the time stamp entry is the time of day;

None of those seem like they should be problematic given the documentation. However, I tried taking out each particular column from the table individually – and the problem persists no matter which ones I have in place, including if I just have them as a table with a single column. So it doesn’t appear to be any one of them in particular.

So I guess I’m not sure what the “unsafe data” here is.

The context for this, incidentally, is around the idea of time travel where the actions that the player takes are recorded in a table so that, later, when a future version of the player goes back to that location and time, those actions can be played out again by the “previous self.”

Inform’s explanation of this is less than great. But note the first half of the paragraph:

One unfortunate restriction must be kept in mind. Some of what is stored in tables is solid information whose meaning never changes: the number 342, for instance, means the same to everyone. But other information depends entirely on the current location of certain structures in memory - for instance, a rule is internally referred to by its memory location. This potentially changes each time Go or Replay is clicked, and so it is not safe to pass it from one copy to another, or from one project to another. The only tables which Inform allows us to write into files are those containing “safe” data: numbers, units, times of day and kinds of value with named alternatives. Scenes, rules or rulebooks, in particular, are not allowed.

And crucially, objects are also memory addresses. The “not safe to pass it from one project to another” part is key. Another project would be able to understand 5 or “abc” just fine. But what would Doctor Frankenstein’s laboratory mean to a project that doesn’t have that same exact room in it?

Look at the example “Labyrinth of Ghosts” for a way to work around this. In that example, each room is given numerical coordinates, because numbers are safe to write to a file. You can do the same with the printed name, if that’s unique and unlikely to change between versions of your game.

Alternately, if you’re not worried about compatibility across versions of your game—you’re sure the file will always be read by the same version of the game that wrote it, like with save files—you can use a little bit of I6 to circumvent Inform’s safety checks.

To decide what number is (O - an object) serialized: (- {O} -).
To decide what object is (N - a number) unserialized: (- {N} -).

Now you can convert your agent and location to numbers when writing them to the table, and back to objects when reading from it. Just change the table columns to numbers (safe to write to files!), then “now the actor entry is the player serialized”, “now the player is the actor entry unserialized”, and so on.

5 Likes

Fantastic explanation! Thank you very much for digging into this. I’ll play around with this but initial experiments already show that the “to number and then back to object” approach works just fine.

Again, much thanks.

Glad it helped!

The one caution is you need to make sure the file is being read by the same exact game version that wrote it, because otherwise unserializing a number might give an invalid object, and the game will crash. There are a few ways to handle this, but an easy one is to also save the game serial number (in the same file or another file), and blank out the whole table if it doesn’t match when restoring.

Stored actions are also a bit messy to save and restore because they contain references to the actor, noun, and second noun—which are, of course, objects. I’ll have to think a bit more about a useful way to serialize them.