Defining a base kind that could be a thing or a container

Several years ago, I wanted to define a kind that could be either a thing or a container.
My kind has properties and all sorts of rules associated with it, which I only want to define once.
I did this in an older version of Inform 7 by way of a hack that redefined a container as my kind.

E.g.

A magic item is a kind of object.
Every magic item has a a number called enchantment bonus.
[Define all sorts of other properties and rules for magic items]

[Hack - this used to work in Inform 7 version 6M62]
A container is a kind of magic item.
A magic container is a kind of container.

This hack was the only way I knew of to make things like magic backpacks, that were both containers and magic items.

When I try this hack now, the compiler chokes:

inform7: no permission for 'K5_container' to have this property: 'P_enchantment_bonus'
  >--> An internal error has occurred: inter error. The error was detected at
    line 272 of "inter/building-module/Chapter 3/Produce.w". This should never
    happen, and I am now halting in abject failure.

The properties and rules for magic items are extensive, so I don’t want to duplicate them for both magic items and magic containers. I just want to define the properties and rules once for one base kind, and then be able to define specific kinds of magic items and magic containers that have these properties and are covered by these rules.

How do I do this?

In programmer speak, I want to define rules and properties for an interface, not a class.
Or, I want multiple inheritance, because I need my subtypes to be containers, not just have a part that’s a container.

1 Like

As written, that doesn’t work in either 6M62 or the current version (10.1.2):

Problem. You wrote ‘A container is a kind of magic item’ , but that seems to contradict ‘A container is a kind of thing’ , as a magic item and a thing are incompatible. (If a magic item were a kind of a thing or vice versa there’d be no problem, but they aren’t.)

If I change the first line to “A magic item is a kind of thing,” then it compiles in both 6M62 and the current version.

1 Like

It’s not really a hack, or at least it’s a supported hack. :) The effect is to place “magic item” in the kind inheritance tree between “thing” and “container”. I don’t remember if the documentation talks about this, but it’s allowed.

You could skip the “magic container” declaration, since with this setup every container is magic.

1 Like

Sorry, in the original post, I meant A magic item is a kind of thing rather than kind of object.
I still get that error in 10.1.2, saying is a kind of thing.

6 years ago when I left off on this project, I was in the process of converting to 6M62 from an even older version (that the hack definitely worked in), so it might have only worked in the older version and I gave up on the project when I tried migrating to 6M62.

I guess I can try living with all of my custom containers really having a container as a part (called the “inside”), and try redirecting various verbs to make it seem like a container… I hope there isn’t an endless list of quirks and workarounds I’ll have to do to hide the container being a part…

1 Like

The “official” way to do multiple inheritance in I7 is to use properties instead of kinds. For example, a thing can be scenery and also a container or supporter, because “scenery” is a boolean property, not a kind of thing. And you can still write rules about trying to take scenery and so on.

This does waste some space if you have a lot of special properties, since you have to define them on things instead of magic items. But that’s the price Inform users pay for abandoning multiple inheritance.

(Funnily enough, I6, which does have multiple inheritance, handles containers and supporters as binary properties instead of classes. Historical baggage.)

1 Like

Sorry. There’s an endless list of quirks and workarounds you’ll have to do to hide the container being a part.

Just let all things have the all the magic properties and either have an either-or magical or mundane property or make a definition in terms of another property (like whether enchantment bonus is -32768) to delineate magic things from non-magic things. Then just check whether something’s magic before passing it to a notionally magic thing based rulebook or an activity notionally on magic things. Or go ahead and pass it if you prefer doing something like:

Zapping is a thing based rulebook.
This is the can't zap mundane things rule:
  if the container in question is mundane, rule fails.
The can't zap mundane things rule is listed first in the Zapping rules.

(For any rulebook based on an object or subkind thereof, container in question and supporter in question can be used to refer to the object the rulebook was invoked with.)

You can also have phrases like:

to cast (m - magic thing): [special effect]

to cast (t - thing): do nothing.

It’ll go to the right place 'cause it’s like rule-ordering: more specific goes first (but there’s no fall-through.)

I talked about OOP-ish effects in I7 a couple times previously:

2 Likes

Personally, magic/mundane (that is not magic) is better treated as a boolean, and in a fantasy world, the player’s holdall object is the archetypal magic container (bag of holding, toothed or not :wink: ) and implementing the flag as a boolean eases much implementing a “detect magic” spell
Actually, I have fooled around in past on this concept, using an empty string as “non-magical” flag, and the string is the description of the aura of the magical object:

A thing has some text called the emanation.
Probing is an action applying to one thing.
Understand "probe [something]" as probing.
Check probing: if the emanation of the noun is "", say "totally mundane, no traces of Aura from [the noun]."  instead.
Carry out probing something: 
    say "[emanation of the noun][paragraph break]".

Best regards from Italy,
dott. Piergiorgio.

1 Like

The example I gave for a magic item was contrived just to illustrate the problem, but distracted from the real issue. My actual use case is below, minus the pages and pages of rules for donning and doffing.

The problem remains that I can’t make container a kind of my type, if my type has properties, or at least a list of text property, which is what I need.

"Slotted Wearing Test" by Nels Olsen

Chapter - Slotted Wearing

Section - Body Parts

A body-part is a kind of thing.  It is usually fixed in place.
Every body-part has text called slot-type.

A head-body-part is a kind of body-part.  The printed name is "head".  The slot-type is "head".
A head-body-part (called head) is part of every person.

A back-body-part is a kind of body-part.  The printed name is "back".  The slot-type is "back".
A back-body-part (called back) is part of every person.

[NOTE: All the other body parts left out for brevity.]

Section - Wearable Slots

A wearable-slot-filler is a kind of thing.  It is usually portable.  It is usually wearable.
Every wearable-slot-filler has a list of text called required-wearable-slots.

Wearable-slot-filling relates one wearable-slot-filler (called the slot-filler) to various body-parts.
The verb to wearable-slot-fill means the wearable-slot-filling relation.
The verb to wearable-slot-receive means the reversed wearable-slot-filling relation. 

Definition: A thing (called the item) is slot-wearable if the item is wearable and the item is a wearable-slot-filler.
Definition: A thing (called the item) is slot-worn if the item is worn and the item wearable-slot-fills something.
Definition: A body-part is wearable-slot-filled if it wearable-slot-receives something.

Slot-wearing relates a person (called P) to a wearable-slot-filler (called the slot-filler) when the slot-filler wearable-slot-fills a body-part that is part of P.
The verb to slot-wear means the slot-wearing relation.

[HACK] A container is a kind of wearable-slot-filler.  It is usually not wearable.
A wearable-slot-filling-container is a kind of container.  It is usually wearable.

Chapter - The Adventure

A helmet is a kind of wearable-slot-filler.
The indefinite article is "a".
The printed name is "[Indefinite article] helmet". 
The required-wearable-slots are { "head" }.

A backpack is a kind of wearable-slot-filling-container.
The indefinite article is "a".
The printed name is "[indefinite article] backpack".
The required-wearable-slots are { "back" }.

Bob is a person.
Bobs backpack is a backpack.
Bobs helmet is a helmet.

The Dungeon Entrance is a room.  "Here you are at the entrance to the dungeon.  You better don your gear."
Bob is in the Dungeon Entrance. 
Bobs backpack and Bobs helmet are in the Dungeon Entrance.
1 Like

Thanks for the more detailed test case. I now see this error (under 10.1).

I trimmed it down to this:

"Slotted Wearing Test" by Nels Olsen

A wearable-slot-filler is a kind of thing.  It is usually portable.  It is usually wearable.
Every wearable-slot-filler has a list of text called required-wearable-slots.


[HACK] A container is a kind of wearable-slot-filler.  It is usually not wearable.
A wearable-slot-filling-container is a kind of container.  It is usually wearable.


A helmet is a kind of wearable-slot-filler.
The indefinite article is "a".
The printed name is "[Indefinite article] helmet". 
[The required-wearable-slots are { "head" }.]

A backpack is a kind of wearable-slot-filling-container.
The indefinite article is "a".
The printed name is "[indefinite article] backpack".
[The required-wearable-slots are { "back" }.]

Bob is a person.
Bobs backpack is a backpack.
Bobs helmet is a helmet.

The Dungeon Entrance is a room.  "Here you are at the entrance to the dungeon.  You better don your gear."
Bob is in the Dungeon Entrance. 
Bobs backpack and Bobs helmet are in the Dungeon Entrance.

Curiously, if you change the property line to

Every wearable-slot-filler has a number called required-wearable-slots.

…then there is no error! It only seems to arise on heap types like texts and lists.

So, as you said back at the beginning, this is a compiler abject failure:

An internal error has occurred: inter error. The error was detected at line 272 of “inter/building-module/Chapter 3/Produce.w”. This should never happen, and I am now halting in abject failure.

Additional error messages on console:

inform7: no permission for ‘K5_container’ to have this property: ‘P_required_wearable_slots’
inform7: no permission for ‘K5_container’ to have this property: ‘P_required_wearable_slots’

This means that what you’re doing is legal – at least it was legal in 9.x, and there’s no reason that should have changed. What’s changed is that there’s a bug in the current compiler. I’ll file that.

Until that’s fixed, I guess you could write

Every thing has a list of text called required-wearable-slots.

This wastes a bunch of memory but it compiles.

2 Likes

Filed as https://inform7.atlassian.net/browse/I7-2407 .

3 Likes