By default, Inform 7 has a “dual object hierarchy”: there’s the containment tree, and the “part-of” tree. This complicates various parts of the library that have to switch back and forth between the trees, with functions like CoreOfParentOfCore (the part-ancestor of the containment-parent of the part-ancestor of an object).
Dialog instead has a single hierarchy, plus a property on objects that indicates which relation it has to its parent. This means that, for example, an object could be both a container and a supporter without ambiguity: some of its children would have their relationship property set to “on”, others to “in”. “Worn” and “part-of” are also implemented as relationships in the hierarchy.
How feasible would it be to implement something like this in Inform? The main difficulty I’m foreseeing is implementing the setters for “carried by”, “worn by”, etc, since I don’t know of a way to define a custom setter for an I7 relation.
The deeper problem (which I’m sure is why Inform hasn’t already done this!) is that there’s a lot of low-level code that relies on the old-style object tree.
(As you know, but not all readers will know, the difference between Inform’s containment tree and Dialog’s is this: In Dialog, the container/supporter flag is on the child. In Inform, the flag is on the parent. Inform’s “part-of” tree is a patch on top of that older system.)
You can’t get all of this by replacing relation code. For example, Inform’s list-writer works by iterating the old containment tree. (It ignores part-of relations entirely!)
Yes, but there shouldn’t be any particular reason why I7 couldn’t implement something similar, similar to how the part-of tree is separate (each child part has a property that specifies what it’s a part of, and conversely the assembly knows which parts it contains – and these are nominally independent from the containment relationship). It’s just that moving an object also explicitly clears that part-of relationship as well, overruling the normal independence of relations.
So I7 could in principle use the traditional parent(x) model only for containment and use a separate property to track support, thereby allowing an object to be both. But this would require all the existing I6 code that deals with supporters to be tracked down and updated to the new model.
It’s probably just that this case is rare enough that nobody has wanted to bother, especially given that you can define objects with multiple parts as required to work around it. (And there are other complexities as recently discussed with getting things like lighting to work as expected anyway.)
If you were wanting to define a new kind of relation, you’d probably want to steer clear of the I6 layer entirely and do as much as possible in pure I7; those are already independent trees.
Also causes all the problems of multiple trees, which is what I’m hoping to avoid. The separate contained-in/part-of trees are already responsible for some weird and extremely difficult-to-diagnose bugs in the existing library. Dialog’s model seems cleaner and easier.
I suppose this should be filed under “if the Inform library can ever get rebuilt from the ground up”, which comes sometime after “if Inform becomes open-source”.
My point is that I think I7 is trending towards multiple independent relations anyway, ie. multiple trees. Which implies that I6 is in the wrong by trying to smoosh together containers and supporters in the same tree.
Though yes, the contain/support/part relationships are a bit peculiar in that they’re not quite independent, they all represent a kind of location and thus if you change one you have to “reset” the others.
Actually, after playing with this a bit, perhaps this demonstrates some of the current weirdness you’re referring to?
There is a room. In it is a truck and a couch.
The truck is a vehicle.
The tailgate is part of the truck. It is an enterable supporter.
The couch is an enterable supporter.
Test me with "sit on couch / stand on couch / sit on tailgate / stand on tailgate / g"
You’d expect that the couch and the tailgate behave similarly with regard to sitting and standing, but they don’t.
I suppose this should be filed under “if the Inform library can ever get rebuilt from the ground up”, which comes sometime after “if Inform becomes open-source”.
It’s all in template files, which can be replaced from the ground up in the current system. Writing the code is the hard part.
The next release will make this easier, though, by separating the original world model from the core “Basic Inform” language.
You also want tree iteration to be efficient. (E.g. scope search, where you want to start at the room and traverse all the children recursively.) The contain/support/component relations are hardcoded to be fast that way. I7 relations in general aren’t.
True, but is it possible to make a relation with a custom getter and setter in I6?
That is, is it possible to write something like…
[ ContainmentRelationSet x y ;
! do some checking whatever
move x to y;
x.relation = REL_IN;
];
…in such a way that now the needle is in the egg calls my custom routine? That seems to be the sticking point for making a Dialog-style tree: I know I can write a custom getter for a relation (with the X relation relates…when…) but I don’t know if custom setters are possible.
Yes, and this clarification should probably be clarified further: Dialog does in fact have flags called “container” and “supporter” that go on the parent. But these flags only determine if the player is allowed to put things in or on the object, respectively. They say nothing about the relation of the currently present children (unlike in I6/I7).
But the story author is free to put things in or on any object, regardless of how the flags are set. Thus you might have a hook on the wall, and “look on wall” would say “on the wall is a hook”, but “put marble on wall” would result in something like “you can’t put things on the wall”.
There does seem to be some magic going on somewhere, though.
The Standard Rules define the containment relation and associated I7 assertion verbs, but doesn’t appear to have anything that specifies how this translates into I6, unlike most other kinds of I7->I6 translations.
Presumably there are specific relations that the I7 compiler recognises and translates without any ability to customise this or do something similar for new relations. (Unless it’s merely undocumented, or I missed it somehow?)
(Looking at some generated output, some of the magic appears to be in a generated Rel_Handler_NN, but I don’t think that’s of any help in fiddling with it.)
Yes. If you were starting from scratch with new relations, you’d have to (a) write your own magic low-level code (which is what I was saying) and then (b) figure out how to attach it to the relation declaration (which is what Draconis was asking, but I don’t know the answer).