[I7] Simple game where compiler ignores an object?

I’ve been toying with Inform 7 and have come across a simple situation that has me baffled. (was: “been baffled” D’oh!)

Please consider this (obviously simplistic) game:

"Collect The Chairs" by Bruce Addison

Beginning is a room.

A chair is here.

Finale is north of Beginning.

A chair is here.

When I play this game the first room (Beginning) has a chair present. When I go to the second room (Finale), there’s no chair.

The “Translating the Source” (this is build 6G60) states:

The Index for Kinds shows 2 things, 1 of them a person (the player). If I rename the second chair to a “qwert” (for example), I get the expected 2 rooms and 3 things.

I guess I have two questions here:

  1. Do others get the same result when they compile the above source? (I just want to be sure it isn’t, for example, an issue with the installation on this machine.)

  2. Assuming this is not unique to this machine, why doesn’t Inform 7 at least warn that it’s omitting an object?

This appears to be a compiler bug, but it’s a subtle one.

I7 creates objects by inference from your declarations. If you make a declaration twice (“A chair is in Finale. A chair is in Finale”) then you’re only creating one object – the chair object satisfies both statements.

What you’re doing is equivalent to “A chair is in Beginning. A chair is in Finale.” This should register as a contradiction, because the chair can’t be in both places. However, it looks like “here” is being interpreted late and the compiler fails to detect the contradiction.

And if you want two chairs, you have to begin with “A chair is a kind of thing.”

Also, this works as expected, placing a chair in each of the rooms. (I have no idea what that tells you about the nature of the bug.)

A chair is a kind of thing.

Beginning is a room.

Here is a chair. [or: One chair is here.]

Finale is north of Beginning.

Here is a chair. [or: One chair is here.]

I see no bug. The objects are calculated evidently after the rooms (all of them). This means that in case 1 we have two times the same chair, while in case 2, providing we have a kind, Inform creates 2 chairs. I puzzle where they are, if one per room or two in the same. (at the office, can’t test it now).

The bug (in the original code) is that the chair is placed in the Beginning room, even though there is a “chair is here” declaration which should interpret “here” as the Finale room.

The compiler should report an error (chair declared to be in two different places).

Since this is only my second post on this forum, I feel that I ought to say something about my motives here.

I have programming experience and am in the process of comparing I6, I7, and TADS 3. Right now I don’t think I7 is for me. That’s just my experience; I can’t deny that others with different backgrounds are creating well-regarded work with it.

What I’m talking about in this thread is something that came up in my evaluation. It isn’t affecting any current work. I think it might be confusing for non-programmers to initially understand what’s going on here. If I’m on the only person who thinks this is a problem, I’m OK with that. :slight_smile:

This was one of my first thoughts. Again, I wasn’t sure why a contradiction wasn’t detected.

When I implemented the two chairs in I6 and TADS 3, I did so via classes. (I also implemented each of them with a unique internal name.) In I7, initially doing so as a kind never crossed my mind.

And if “Collect The Chairs” were a real game, “chair” arguably should be implemented as a kind. One reason is because a chair is an enterable supporter (for example). Another reason I’ll get to below.

A possible problem here is that, in I6, I can implement the I7 game above. (I hope it won’t win any awards.):

[code]Constant Story “Collect The Chairs!”;
Constant Headline “^(A Proof of Concept)^”;

Include “Parser”;
Include “VerbLib”;

[ Initialise;
location = Beginning;
];

Object Beginning “Beginning”
with
description “”,
n_to Finale,
has light;

Object chair1 “chair” Beginning
with name ‘chair’;

Object Finale “Finale”
with
description “”,
s_to Beginning,
has light;

Object chair2 “chair” Finale
with name ‘chair’;

Include “Grammar”;
[/code]

So, in I6, I can implement the two chairs as separate objects without creating a class. I do, however, have to use a separate obj_id for each in the source code. This is how I initially assumed that I7 would handle it. I don’t think my initial understanding is obviously wrong. A compiler warning would have sufficed.

After posting last night, I remembered the William Tell example from the 3rd edition of The Inform Beginner’s Guide [covering I6]. (This is the Arrow class, introduced on pp. 84-85.) If I were seriously creating a game called “Collect The Chairs,” I probably should use a collection for chairs. Each chair would be a separate object yet identical to other chairs. This would likely be equivalent to chair as a kind in I7.

Here’s a transcript based on Felix Larsson’s sample code above:

This behavior would be better suited to an actual game called “Collect the Chairs.”

James, perhaps it isn’t a bug (maybe a warning would suffice). However, I don’t understand why what you describe as case 1, “we have two times the same chair,” is the only correct reading of the sample code.

Suppose after Beginning, instead I wrote “Here is a qwert.” After Ending, instead I wrote “Here is a uiop.” When I run this game, I see a qwert in Beginning, and an uiop in Ending. Each is a separate object, identifiable either by its name or its starting location.

Now suppose I changed the uiop to a qwert. Why shouldn’t I be able to do this? Although what were two separate objects now have the same name, each is still identifiable by its different starting location. If in fact I can’t do this, I would hope at the very least the compiler would say something. (Having both example objects as portable probably doesn’t help.)

I hope the above doesn’t sound too defensive; I realize you posted at work on a Monday morning. :slight_smile: It’s just that I’m aware of the usual programmer answer: “You should use a kind (class) here.” I’m not convinced that (a) this is obviously the only correct answer [in I7 can I refer to individual instances of a kind if I do this?], (b) yet, if it is in fact the only correct answer, ideally the end-user needs to know about this implementation issue.

To restate what I wrote above (before zarf posted), I don’t see the bug this way. My initial thought was that (ideally) I7 would do something like my sample I6 game above. If it couldn’t, it should at the very least raise a warning.

It’s possible I’m mistaken. The use of portables might confuse things a bit.

By ‘A chair is here’ you give the object its internal name. Inform 7 then coies that into the printed name (i.e. the I6 short_name).
The I7 equivalent of what your doing in I6 is rather: The chair1 is in the Beginning. The printed name is "chair".The chair1 is in the Beginning. The printed name is "chair". (which compiles fine)-

So, part of the problem comes from the potentially misleading surface similarity of Inform 7 to natural English: ‘A chair’ in English means a chair, i.e. one exemplar of the chair kind; in Inform 7 it means the object (which can be preceded by definite and indefinite articles) called ‘chair’. Part of the problem comes from the fact that the compiler failed to protest, but the fact that it didn’t is, as we’ve seen, a bug that depends somehow on the use of I7 syntactic sugar (‘is here’); if you’d used ‘A chair is in the Beginning. A chair is in the Finale.’ there would have been an error message.

If you drive the comparison all the way home, the two languages behave the same in these cases, actually.

The analogous I6 program would look like:

Object Beginning;
Object -> chair;	

Object Finale;
Object -> chair;

I6 correctly complains that you are reusing an object identifier. (“Error: Expected name for new object or its textual short name but found chair”)

To avoid this, you use two different identifiers; you make objects named chair1 and chair2, just as you did. Then you have to ensure that the objects are displayed as “chair”, and parsed as “chair”. Your I6 code also takes care of that, with the short name and name properties.

The analogous I7 code would be:

Beginning is a room.

A chair1 is here. The printed name is "chair".
Understand "chair" as the chair1.

Finale is north of Beginning.

A chair2 is here. The printed name is "chair".
Understand "chair" as the chair2.

You can see that this is built exactly the same way – we define two objects with different names, and then set the printing name and the parsing to match.

This doesn’t behave quite the same as the I6 version; if you bring the chairs into the same room, a command “x chair” will provoke an unresolvable disambiguation message. (“Which do you mean, the chair or the chair?”) To make it really work right, you’d want to start with a class, rather than two separately-created objects. But my point here is that your example is not really a distinction between the languages.

There are meaningful distinctions between the languages. In I7, if you repeat a declaration exactly – “The chair1 is in Finale. The chair1 is in Finale.” – that’s not an error; you are describing one object. But this is inevitable, because you can make lots of statements about chair1. “Chair1 is a thing. Chair1 is in Finale. Chair1 is proper-named.” By any sensible interpretation this should define one object, not three. And if the statements contradict, the compiler should complain, not silently duplicate the object.

I agree with Felix’s point – sorry for cross-replying – that it’s the English article “a chair” which is confusing here. I7 almost never pays attention to the distinction between “a” and “the”. In fact I think it never does. (Although if you leave the article off entirely, I7 infers that the object is proper-named.)

Because that’s how Inform7 works. When you declare an object, you give it a name and a printed name (in case none of the latter is provided). So:

A chair is in the Lobby.

Makes an object which name is “chair” and which printed name (what you read in runtime) is “chair”.
You can avoid this by coding:

A ch_obj is in the Lobby. The printed name is "chair".

So the name is “ch_obj” and the printed name is “chair”.

@ zarf. I understand the fact it is indeed a bug. In many other similar occasions, I7 would have stopped compiling, saying something on the lines of “You wrote ‘a chair is in the lobby’, buy in another place you said ‘the chair is in the living room’ etc etc.”

I don’t know why this happens. But… who better than you to find a solution? :slight_smile:

Uh, I can’t fix compiler bugs. Graham supports the compiler.

That must be a bug, then. A bug in zarf. :stuck_out_tongue: