Handling Kind of Things

Hi all,

Still cracking the Inform7 puzzle. I must be missing something blatantly obvious here, but here goes…

Basically I define a book kind of thing so I can then (re)define verbs related to books and have some generic handling of books.

However for reasons I do not quite understand is that using a plural form / singular form gives opposing results for referring to the thing and its kind:

>[1] x book
You can't see any such thing.
>[2] x books
You see nothing special about the manual.
>[3] x manual
You see nothing special about the manual.
>[4] x manuals
You can't see any such thing.

I guess I can add some Understand statements here, but is this indeed the ‘correct behaviour?’ At the least I would expect to be able to refer to the manual as a book…

1 Like

“test me with “x book / x books / x manual / x manuals”.”

It knows what “manual” is as you’ve defined it.

It doesn’t know “manuals” because you need an understand rule.

I think it doesn’t recognise “book” because it’s a kind of thing rather than a thing.

I guess it turns “books” into the manual because it worked out that it’s the plural of a kind of thing that exists in the room.

I wonder whether it would be easier to have a different name for the kind than for any thing of that kind.

1 Like

In some examples I see even weirder stuff. If I replace the above with

A book is a kind of thing.
A manual is a kind of book.

Then the test would result:

>x book
You can't see any such thing.
>x books
You can't see any such thing.
>x manual
You see nothing special about the manual.
>x manuals
You see nothing special about the manual.

So now I can refer to the manual in singular or plural form but now it is suddenly no longer considered to be a book… Trying to wrap my head around how this works…

1 Like

Normally, when you declare a kind, you also want to put in some Understand lines for it. You don’t get them for free.

A book is a kind of thing.
Understand "book", "volume", "tome" as a book.

A manual is a kind of book.
Understand "manual" as a manual.

You don’t need to declare the plural kind this way. The compiler sticks in “manuals” as a plural synonym for free. Honestly I think that’s a mistake – it’s confusing, as you found, and occasionally you don’t want it.

You can do that manually (as it were) by saying

Understand "books", "volumes", "tomes" as the plural of books.

Another wrinkle is that you’re declaring an anonymous object here:

In the laboratory is a manual.

It’s more common to give the object its own name:

The Manual of the Planes is a manual in the kitchen.

In this example, you get “manual” (and “planes”, and “of”) as synonyms automatically, because they’re part of the object name. This very often makes everything work right without further fiddling.


For publicly-named things, each of the words in their object name can refer to them and in addition, so can exactly one plural: the plural for its base kind, but not for the other kinds that kind is a subkind of. So a vehicle gets “vehicles” but not “containers” or “things”. We wouldn’t want “containers” to mean vehicles in the parser, so that’s good. But, yeah, I wish there were a way to say “don’t automatically add the plural” short of making something privately-named.

(This just rehashes what Andrew already said to emphasize the “you get only the narrowest plural kind” part.)


Fairy Godmother here…

"Depluralise" by PB

Chapter - Scenario

Section - The Bears' Cottage

The Three Bears' Cottage is a room.

The description of the player is "On account of your flowing blond tresses, everybody calls you Goldilocks."

A bed is a kind of thing.
A chair is a kind of supporter.
A breakfast is a kind of thing.
the plural of breakfast is porridges.
A table is a kind of supporter.

The Kitchen Table is a table in the cottage.
Daddy Bear's Porridge, Mummy Bear's Porridge and Baby Bear's Porridge are breakfasts on the Kitchen table.
a Big Bed, a Medium-sized Bed and a Tiny Bed are beds in the cottage.
a Big Chair, a Medium-sized Chair and a Tiny Chair are chairs in the cottage.

Section - Trying

Trying is an action applying to one thing.
Understand "try [things]" as trying.

Check trying when the noun is not a bed and the noun is not a chair and the noun is not a breakfast:
	say "[We] don't really want to try that." instead.

Carry out trying Daddy Bear's Porridge: say "It's much too salty!".
Carry out trying Mummy Bear's Porridge: say "It's much too sweet!".
Carry out trying Baby Bear's Porridge: say "It's just right! Yum Yum!"; now the noun is nowhere.
Carry out trying Big Bed: say "It's much too hard!".
Carry out trying Medium-sized Bed: say "It's much too soft!".
Carry out trying Tiny Bed: end the story saying "It's just right! Yawn! Zzzzzzz.".
Carry out trying Big Chair: say "It's much too big!".
Carry out trying Medium-sized Chair: say "It's much too wobbly!".
Carry out trying Tiny Chair: say "It's just right!"; move the player to the noun.

Chapter - Testing

Test me with "try chairs/depluralise baby porridge/try porridges/try baby porridge/x tables/depluralise table/x tables/x table/depluralise tiny bed/try beds/try tiny bed"

Chapter - Depluralising

To depluralise (o - an object): (- RemovePlural({o}); -).
Depluralising is an action applying to one visible thing.
Understand "depluralise [any object]" as depluralising.

Carry out depluralising: depluralise the noun.

Report depluralising: say "[The noun] has been depluralised.".

Include (-
[ RemovePlural o f p x y a n ;
! print "checking for null object...";
if (o == 0) rfalse;                  ! null object
! print "checking name property...";
if (~~(o provides name)) rfalse; ! no name property
n = o.#name/WORDSIZE;  ! number of names in array
! print n, "names in array...";
if (n < 2) rfalse;                   !  1 or no names in array
p = o.&name;                     ! address of name array
f = p-->0;                           ! first name in array
! print "first name is ", (address) f, "...";
for (x=1:x<n:x++){
	y = p--> x;                  ! read dictionary address of next name in array
	! print "checking ", (address) y, "...";
	a = y + #dict_par1;     ! 1st dictionary parameter
	if ((((a->0) & (4)) == 4))  { ! plural name
		! print "plural found- substituting ", (address) f, "...";
		p-->x = f;            ! substitute with first name in array

That code makes me feel like the prettiest one at the ball!


That code makes the “privately-named” plan look awfully easy. :)


Fair point.

Unless you have a large number of objects (to expunge plurals from) that you can now loop through :)

1 Like

Seems like the default plural is always the second entry, so with a few small crimes against readability:

to remove default kind-name plurals: (- objectloop(({-my:0} provides name) && 
  ({-my:0}.#name > WORDSIZE) && 
  ((({-my:0}.&name-->1)->#dict_par1) & 4))
    {-my:0}.&name-->1 = {-my:0}.&name-->0; -)

when play begins: remove default kind-name plurals.

Also, one will want to up DICT_WORD_SIZE to at least 10 or get some odd behavior with direction, container, and supporter.

1 Like

Sadly, this is not the case (as uncommenting the print statements in my example will demonstrate).

EDIT: it’s usually the LAST entry in the name property array. So try this:

to remove default kind-name plurals: (- objectloop(({-my:0} provides name) && 
  ({-my:0}.#name > WORDSIZE) && 
  ((({-my:0}.&name-->({-my:0}.#name/WORDSIZE-1))->#dict_par1) & 4))
	{-my:0}.&name-->({-my:0}.#name/WORDSIZE-1) = {-my:0}.&name-->0; -)

EDIT2: built-in (but not author-defined) directions (inevitably) are an exception, in that the pseudo-plural is the SECOND entry (or SECOND-to-last) entry in a 3-name array: e.g. with name 'north' 'direction' 'n',, so ‘direction’ won’t be removed by the above code on 2 counts- firstly because it’s not flagged in the dictionary as a plural; secondly because the pseudo-plural is not the last name in the name property array


The weird thing with instances of directions, supporters and containers is that the default-plural-name-of-kind compiled to their name property is ‘direction’, ‘supporter’ and ‘container’ respectively, none of which are flagged in the dictionary as plural words (because the true plural forms ‘directions’ etc. exceed the standard 9-character dictionary word-length limit).

This means that neither my nor Zed’s code as written (which depend on replacing plural-tagged entries in the name property) will remove these ‘spurious’ plural names from instances of directions, supporters or containers. i.e. even after ‘depluralising’ you can still type ‘take containers’ (effectively truncated by the parser to ‘take container’) and take a container in scope, or type ‘take every container’ to take all of them.

I presume the same issue would apply to any author-defined kinds with a kind name 9 characters or more in length.

EDIT: confirmed that this is the case: in my example, if the plural of breakfast is not redefined as porridges, then a non-plurally-tagged breakfast is inserted to the name properties of all instances of the kind ‘breakfast’.

If this goes in an extension, I think it would be worth redefining the plural names to get around this issue: make them be “dirs”, “conts”, and “supps” or whatever, and then the plural-nuking code can remove them as usual.

1 Like

Or, if not compiling for z-code, do as Zed suggests and

Use DICT_WORD_SIZE of 10. [or some value higher than 10]

If the author has added “understand” statements, those will be after the default plural. But I drew a very silly conclusion from testing things with single-word object names. So:

Include (-
[ RemoveKindPlurals o i;
  objectloop(o provides name && (o.#name > WORDSIZE))
    for (i = 1 : i < o.#name/WORDSIZE : i++ )
      if (((o.&name-->i)->#dict_par1) & 4) {
        o.&name-->i = o.&name-->0;

Here’s another wrinkle: look what happen with player's holdall:

with name 'backpack' 'player^s//p' 'holdalls//p'

For the holdall’s multiple-word self, you get two automatically-created kind-name plurals.

The thing I said last year works, too.

But on balance this “overwrite plurals with a second copy of the first word” approach or “turn the plural into something the parser won’t accept” are so kludgey they make either of making everything privately-named or post-processing the I6 before compiling it look good in comparison.

perl -pi.bkp -e $'s{\'(directions|things|people|rooms|doors|containers|supporters|devices|vehicles|men|women|animals|backdrops|regions|player\\^s|holdalls)//p\';?}{}g' auto.inf

Of course, the best solution would probably be an option like “use no automatic plural names”. I just have to figure out the guts of the compiler well enough to know how to do that.

I think there’s room for disagreement here.

Adding a post-processing and separate compilation step where you also have to maintain an accurate parallel list of kind name plurals doesn’t seem like an author-friendly advance on automatically replacing all auto-generated plurals, which simply works in a fire-and-forget fashion with minimal included code. It will also take 'player^s//p' 'holdalls//p' in its stride as long as you don’t break out of the loop with the first replacement (as in my originally-posted code) and it will also happily ignore any plurals added via “Understand…”, which are incorporated into the routine called by the parse_name property rather than added to the name property. If you want to just do it with certain objects, just define an either-or property (e.g. An object can be non-plural) and include a filter for that property in your objectloop condition, so you can just write the baboon is a non-plural animal to strip ‘animals’ from the baboon’s names, or an animal is usually non-plural and so on.

Making things privately-named and providing a separate “Understand…” phrase to reinstate the list of name words you’ve just sacrificed isn’t a chore if you only feel the need to do it for a few objects. But to do it for EVERY object you write is a real pain.

So, I guess you pays your money and you takes your choice of the approach that works for you and your situation :slight_smile:

I wouldn’t claim that adding an extra compilation step is friendly to IDE-users. My perl one-liner was just a demo of the concept. Certainly, a more sophisticated post-processor that actually looked at kind definitions within the I6 would be desired for real-world use. The former I could whip up easily enough for an IntFiction post; the latter not so much.