Too many either/or properties?

I have a large v10 project which depends on some complex extensions. Tonight I started getting

[** Programming error: tried to read (something) **]

every time the game executed a particular rulebook. After some investigation I found that eliminating some either/or properties eliminated the problem, no matter which I eliminated. Once I got it working, I tried adding junk either/or properties and the problem reoccurred.

How can I approach this problem (other than eliminating properties)?

So far as I knew, the compiler’s supposed to automatically start representing either-or properties the same way it would a truth state property when it runs out of I6 attributes and keep the difference invisible to you.

Manually switching to explicit I7 properties might get around it.

Latecomer-attribute is a truth state that varies.
thing1 has a latecomer-attribute.

or if you still want adjectives,

Latecomer is a kind of value. The latecomers are hot and cold.
thing2 has a latecomer.

Not sure, though… like I said, I thought this wasn’t supposed to happen.

1 Like

It may be one of the extensions that’s failing to keep up, rather than the compiler.

If Zarf is right, then one of the book sections I just read mentioned how extensions can have special arrays defined that can run out of room, and how to extend them:

https://ganelson.github.io/inform-website/book/WI_27_18.html

Actually I was thinking that an extension might (wrongly) assume that every either/or property is an attribute.

This is just a guess though.

1 Like

Moving extension A into the main text made the problem disappear. Which is great, but I’d like to keep this as an extension, since I wrote it and I find it useful.

Incidentally, it has no I6 inclusions in it, and neither does the main text.

Yeah, thinking about it more, this probably doesn’t have anything to do with how either/or properties are being represented. Something’s going on that’s making something try to read a property from something that’s not an object.

I’d been writing that when you posted. Any possibility you have some ambiguous names in your code and the compiler took something you intended to refer to an object as a reference to something else?

use unabbreviated object names.

and following through with using things’ full names would tell you whether the above is the case, but if your program’s long, it would be a real pain.

If you add two dozen more either/or properties, then comment out extensions one by one, is there a particular extension whose removal fixes the issue?

I’ve found the real problem:

Rule for determining statickness of a thing (called T) when T is enclosed 
by a static room:
	rule succeeds with result true;

Turns out I had defined static for things but not rooms. But for whatever reason this rule never fired (I suppose) until I added this one final extension, even though the extension doesn’t add any things or rooms.

So I don’t know why that is. But in any case I’ve found the real problem. Thanks.

3 Likes

Hm, reminds me of this thread: Why do "an object can be x" and "repeat with o running through objects" refer to different sets of objects?

I haven’t reproduced either case, but I bet this is the deal:

If you say “A thing can be foo”, and then check for “a foo room”, you expect this to silently match nothing (because rooms can’t be foo). If you check for “a foo object”, you expect this to match things but reject rooms.

But I guess that’s not guaranteed? If the foo either-or property is implemented as an I6 attribute, that’s how it works. But if it’s implemented as an I6 property, the rejections aren’t silent; they throw “tried to read (something)” runtime errors.

I don’t know whether this contradicts the documentation or just our assumptions.

(Also I don’t know if I’ve described the previous thread exactly right. It’s late.)

4 Likes

For those still a little unsure, what Zarf is pointing out here is that when an I7 either-or property is implemented as one of the limited number of I6 Attributes (which are like universal either-or properties), every object is given that universal attribute- it’s just that if you write ‘a person can be happy’ only people are allowed to have that attribute allocated by code- such as Mr Bingley is happy or now Mr Darcy is happy. * Any object that is not a person is forever frozen in the default state of not being happy. But you can still ask about that status for objects which are not people without throwing an error- e.g. ‘If Netherfield Hall is happy’ is a valid condition, but one that can never be true.

*this is possible because although every object has a ‘happy’ Attribute, Inform keeps a separate record of which objects are allowed to have the happy Attribute modified and which are not.

If Inform 7 runs out of I6 Attributes to use as either-or properties (there are only a small number that aren’t already used up by the compiler and Standard Rules) it starts to implement them instead as normal I6 properties rather than as Attributes. When this is the case, A person can be happy creates an I6 property which is given only to person objects. Unlike the case with Attributes, any object that is not a person does not have that property at all. Now the condition If Netherfield Hall is happy throws a run-time error because not only can Netherfield never be happy, it doesn’t even have access to the concept of happiness, because it has been given no ‘happy’ property.

The sequence by which either-or properties are implemented- firstly as I6 Attributes then subsequently, when the stock of Attributes runs out, as properties- will be determined by the order that they first appear in the source or are included from extensions. So re-ordering the source code (or transferring an extension into the main source) may cause a property that was previously implemented as a property (and thereby causing a run-time error) to be implemented instead as an Attribute, such that the error disappears.

This error is peculiar to Ver 10 upwards, because Ver 9 and previous had a different method of accessing either-or properties which checked first whether an object provided a property before trying to read it, simply returning false if the property was not provided (which is the same thing that happens for objects which have unmodifiable attributes). Ver 10 skips this check and blunders in trying to read a non-existent property, throwing a run-time error.

This behaviour is easy to reproduce- see the following, which throws an error in Ver 10 but not if compiled for Ver 9.

"Attributes and Properties" by PB

A person can be happy.
A person can be lucky.
A person can be tall.
A person can be short.
A person can be rich.
A person can be poor.
A person can be rude.
A person can be polite.
A person can be famous.
A person can be obscure.
A person can be black.  [up to this point, these either-or properties are implemented as I6 Attributes, hereafter as I6 properties]
A person can be white.
A person can be coloured.
A person can be sad.
A person can be unlucky.

Netherfield Hall is a room.

When play begins:
	unless the Hall is happy:
		say "Netherfield isn't happy.";
	unless the Hall is sad:
		say "Netherfield isn't sad.".
3 Likes

Thanks everyone for figuring out what was going on! Even though the base problem was that I was careless, it’s nice to understand where the behavior was coming from.

Ah, thanks. I noticed that 9/10 difference in the “object can be x” thread but didn’t track down the exact cause.