Topic variables and text in I7

Graham’s comment on one of the related bugs:

I’m afraid it’s true that texts can’t, at present, be used as topics. It would need some run-time trickery, which is not out of the question, but would also lead to a lot of confusion over the meaning of square brackets.

(Not that I really understand what that means.)

Is it just me, or is the way that everyone, including Inform itself, refers to topics, snippets and text inconsistent and confusing?

‘Topic’ appears to have two distinct meanings- either

(1) “unparsed text in the player’s command or passed to an action which might be a ‘topic of speech, writing etc.’”, e.g. ask the robot about the meaning of life

(2) the part of an Understand phrase etc. to be matched against some other textual game content- this sense is referred to by Inform as ‘understand’ text- e.g. ‘Understand “Robby” or “the/-- big/-- metal/-- cyborg” as the robot’. ‘understand text’ can also be matched against a snippet (usually the player’s command) as in ‘if the player’s command includes my_topic:…’

Snippet in Inform also has
(1) a formal meaning as a ‘snippet kind’, existing as e.g. the number 304, representing 4 words of the player’s command starting at word 3.

(2) sometimes a looser usage in its more general meaning of a short (often partial) length of something (usually writing), which seems to be how it’s being used in the bug report you are referring to:

See source text. Topic entries apparently can’t be snippets of text; but Inform 7 seems to think they can and creates an Inform 6 function for converting one to the other. Inform 6 than halts in failure, because it doesn’t know this function.

‘Topics’ in sense (1) (but not sense 2) often appear equivalent to snippets (usually of the command line) in sense (1) of ‘snippet’. Topic variables do however seem to be able to hold topics of either sort, leading to unexpected behaviour, e.g.

"Test" by PB

Instead of telling the player about a topic:
	let t be the topic in row 1 of the Table of Greetings;
	try asking the player about  t.

Instead of asking the player about a topic:
	say "Topic: [the topic understood]".
	
The Lab is a room.

Table of Greetings
topic
"Hello"

Which compiles (when perhaps it shouldn’t- not least because it’s in theory passing a local variable out of scope- see previous discussion above) but leads to:

Lab

tell me about something
Topic: something

rather than what might be expected:

Lab

tell me about something
Topic: Hello

-the topic passed to the ask action in this case just being apparently discarded and the original ‘topic understood’ retained

Text is of course also formally a kind, but the word (for want of a better alternative) is also used more loosely to refer to all sorts of textual entities, including the contents of snippets and topics of all senses.

Aaaargh! I guess in part all this represents a side-effect of natural-language programming where ‘types’ are for example called ‘texts’ rather than ‘strings’ etc.

1 Like

It’s not just you. Be thankful, perhaps, that you weren’t around when there was a hard-enforced distinction between text and indexed text. (As I understand: Text was basically fixed strings, indexed text was strings you could modify, they’re stored in memory differently and indexed text uses more memory, it used to be a big deal to avoid indexed text where possible so as to fit things into stingy virtual machines, but now Inform automatically converts text to indexed text when it needs to because nothing fits into the stingy virtual machines anyway.)

This is how I understand the state of play, but I could be wrong:

“Snippet” really always has to refer to a string of words that are part of the player’s command. This is pretty consistent in the documentation. There however is a line in §22.7 about how “a snippet can be used in place of a text,” which means that you can pass a snippet to a text-valued phrase I think. For instance:

To type (t - a text):
	say "Typing '[t]'."
For printing a parser error: type the player's command.

This is safe because the snippet can be turned into text in an obvious way. Which may be why snippets get loosely referred to as text, because most author’s don’t need to worry about when it’s a snippet and when it’s a text.

The ambiguity in “topic” I think mostly comes from actions “applying to one topic” and “the topic understood.” Here “the topic understood” is really a snippet, so it might help to think of the action as applying to the snippet.

So topics for real are basically always your sense 2. They’re closely related to snippets because basically what you’re always doing is testing snippets against topics, using things like “matches” and “includes.”

(Have I mentioned how much it annoys me that text comparisons use “exactly matches” and “matches” instead of “matches” and “includes” respectively?)

A thing to remember about topics is that even when they’re a straightforward string like “Hello”, Inform is always expecting that they might be a routine like “hello/goodbye/greetings”. That’s why you can never say them or feed them in where a text is expected or anything, because unlike snippets there’s no straightforward way to turn one of these to text.

Which means… I think your example shouldn’t compile. You shouldn’t be able to try asking the player about a topic, since a topic isn’t a straightforward string but a rule for testing strings.

If you want to be able to pass an arbitrary text to a command that applies to a “topic,” you have to put it as text (using the global trick from before). Which incidentally, messes with the player’s command. This:

global is a text that varies.

Instead of telling the player about a topic:
	now global is the subject in row 1 of the Table of Greetings;
	say "Player's command: [the player's command].";
	try asking the player about  "[global]".

Instead of asking the player about a topic:
	say "Player's command: [the player's command].";
	say "Topic: [the topic understood].".
	
The Lab is a room.

Table of Greetings
subject
"Hello"

yields this:

Lab

ask me about something

Player’s command: ask me about something.
Topic: something.

tell me about something

Player’s command: tell me about something.

Player’s command: hello.
Topic: hello.

Looks like, when passing “hello” to asking the player about “hello,” Inform just replaces the entire player’s command with “hello” and sets the topic understood to that.

Exactly! And if Inform does actually want a topic there, I’d call it a bug: it should want a snippet. (And experimentation in 6L38 shows that the compiler treats a double-quoted literal in that context as text, not as a topic: try asking the player about "a/b/c" will act as though a/b/c was typed on the command line, slashes included.)

My thoughts exactly, the odd thing to mere mortals being that Inform 6M62 is happy to cast a topic variable to a snippet here but not a text variable to a snippet- which at the end of the day is just a reference to text tokenised into a buffer using (- VM_Tokenise(buffer, parse) -). But I’m sure Mr Nelson knows what he’s saying when he states it’s a lot more complicated to implement than it seems.

Indeed. Bonkers. Not one of Mr Nelson’s finest moments.

Be thankful, perhaps, that you weren’t around when there was a hard-enforced distinction between text and indexed text.

Yes, I’d heard of this historic peculiarity, and assumed it related to the ways strings were represented in I6 & historically the Z-machine either as compressed constants fixed at compile time (text) or modifiable byte arrays (indexed text)

Only temporarily- the original player’s command is subsequently restored:

"Test" by PB

Before telling the player about a topic:
	say "Before telling- player's command is: [player's command][line break]";
	say "Before telling- topic is: [topic understood][line break]";
	try asking the player about  "oranges";
	continue the action;
	
Instead of telling the player about a topic:
	say "Instead of telling- player's command is: [player's command][line break]";
	say "Instead of telling- topic is: [topic understood][line break]";


Instead of asking the player about a topic:
	say "Instead of asking- player's command is: [player's command][line break]";
	say "Instead of asking- topic is: [topic understood][line break]";
	
The Lab is a room.

Test me with "tell me about bananas"

yields:

[1] tell me about bananas
Before telling- player’s command is: tell me about bananas
Before telling- topic is: bananas

Instead of asking- player’s command is: oranges
Instead of asking- topic is: oranges

Instead of telling- player’s command is: tell me about bananas
Instead of telling- topic is: bananas

Exactly. “Text” was either a packed/compressed string in ROM, or a routine (also in ROM) that would print something when called. So "This door is [if open]open[else]closed[end if]." would be “text”. “Indexed text” was a mutable array of 16-bit or 32-bit words in RAM, so it could be edited on the fly, but couldn’t contain substitutions in square brackets (i.e. I6 routine calls).

Nowadays, all text is text; if you edit it, it becomes indexed text; if you use “the substituted form of”, it also becomes indexed text.