Why do "an object can be x" and "repeat with o running through objects" refer to different sets of objects?

If I try to add a new either / or property to all objects with the following code:

An object can be frotzable.
An object is usually not frotzable.

the set of objects to which the property will be added won’t include the objects Compass, thedark, VPH_2, and VPH_24. And that’s probably a good call - it’s unlikely that I intended to add a property to Compass or thedark, and I don’t even know what VPH_2 and VPH_24 are.

But when I try to iterate over all objects with the following code:

repeat with o running through objects:

the set of objects over which o iterates will include the objects Compass, thedark, VPH_2, and VPH_24. That means that I can’t iterate over frotzable objects with a filtered loop like this:

repeat with o running through frotzable objects:

because those four objects don’t provide the property “frotzable” and I get 8 “[** Programming error: tried to read (something) **]” runtime errors - probably because that kind of filtered loop tries to query the property twice for each object. I can’t even use an unfiltered loop with an if statement like this:

repeat with o running through objects:
	if o is frotzable:

because again, those four objects are included in the loop, and querying the frotzable property in the if statement produces 4 “[** Programming error: tried to read (something) **]” runtime errors. To make it work, I have to add yet another if statement:

repeat with o running through objects:
	if o provides property frotzable:
		if o is frotzable:

Is there a reason for this difference between the set of objects referred to by “an object can be x” and the set of objects referred to by “repeat with o running through objects:”?

And if it’s not a bug, shouldn’t the compiler reject “repeat with o running through x objects” loops that filter the kind “object” by an either / or property? They’ll always produce runtime errors.

And is there a way to filter out those four objects from a loop that I’ve missed?


The deep workings of the compiler are above my pay grade, but in terms of things to try to make this work the way you want, can you just apply the property to things, rather than objects? The set of non-thing objects, as you’ve seen, is pretty abstruse so unless you’re doing something fairly exotic the things approach seems like it should work.


Yeah, I don’t know if you @TheBeardyMan are aware of the difference between Objects and Things in Inform? I probably went a good while without noticing it.

Things are a subset of Objects. Objects includes some abstract entities that you generally don’t want in your way (like the compass directions), but it also includes all Rooms. Rooms are up in the Objects section also because (I presume), by design, authors mostly don’t want the names of rooms getting tangled up in the parsing of player commands.

A good way to quickly see a tree showing the entities hierarchy in your game is – after building a project, click the Index tab on the right in the IDE, then click the third topic, Kinds index. You’ll see everything’s an Object, Rooms are Objects, and Things are another kind of object.

It’s rare you’ll need something the player can interact with to be a new Object, as opposed to a new Thing. So like Mike said, try saying:

A thing can be frotzable.
A thing is usually not frotzable.



The direct reason is that Compass and thedark are created by I6 template code, rather than coming from Inform’s object declaration syntax. You’d get the same result if you included I6 code that looked like

Object foo;

The VPH objects (“ValuePropertyHolder”) come from the Inform compiler, but not from the object declaration system.

So it’s true that “running through objects” is hitting I6 objects that aren’t fully-valid members of the I7 Object kind. This is arguably a bug, but it’s always been like this, and Objects are definitely “if you know what you’re doing” territory.

Interestingly, these runtime errors don’t occur in 6M62. But it’s not because the loop behaves differently – it hits the same I6 objects, which is to say, all of them. The difference has something to do with how properties are handled.