Programatically printing all properties associated with object?

Hi,
Assuming I have some collection of properties, where each kind of object may be described by some subset of them. How can I programatically print the value of each of the properties upon examining an object that kind?

For example:

A ball is a kind of thing.
Color is a kind of value. The colors are red, green and blue. A ball has a color. A ball is usually red.
Material is a kind of value. The materials are rubber, plastic and wood. A ball has material. A ball is usually plastic.
	
The playroom is a room.
The bouncy ball is a ball.

The bouncy ball is in the playroom.

Upon examining the ball, I’d like to print that it’s red and plastic.

Do I need the Property Aggregation rules?
Or can I do it without them?

Thanks!

The provides relation (chapter 13.8) lets you check whether a particular item has a property. However, the compiler can’t cope with if the noun provides color in the example above, because “color” is both a property and a kind of value. You have to give all the properties separate names, which is clunky:

Color is a kind of value. The colors are red, green and blue. 
Material is a kind of value. The materials are rubber, plastic and wood. 

A ball is a kind of thing.
A ball has a color called the color-prop. The color-prop of a ball is usually red.
A ball has a material called the material-prop. The material-prop of a ball is usually plastic.

A star is a kind of thing. A star has a color called the color-prop. The color-prop of a star is usually blue.

The bouncy ball is a ball.
The lamp is a star.

The player carries the bouncy ball. The player carries the lamp.

Instead of examining:
	say "You detect that [the noun] is";
	if the noun provides color-prop:
		say " [color-prop of noun]";
	if the noun provides material-prop:
		say " [material-prop of noun]";
	say ".";

The other problem is that there’s no way to iterate through all properties. You have to check them one at a time in your code, as I’ve done above.

It does the job, though. I haven’t tried to polish up the connectives and the none-of-the-above case, mind you.

>x ball
You detect that the bouncy ball is red plastic.

>x lamp
You detect that the lamp is blue.

>x me
You detect that yourself is.

You may wonder how the SHOWME debug command lists all the properties, if there’s no way to iterate through properties. The answer is that the compiler generates code that checks them one at a time. :)

(Just out of curiosity—since the properties are internally effectively an enum, shouldn’t it be possible to iterate over their numeric values using I6, and look up each one in the object’s property table to see if it’s there or not?)

They’re numeric values, but they’re generated by the I6 compiler. It’s not easy digging out the first and last values. (There’s probably a way but I forget.)

This would, however, get you all the I6 properties, including extremely boring ones used by the parser and world model.

So now we’re crossing the line from “probably hubris” to “definitely hubris”…

But Inform generates a word array called property_metadata which holds the names of all properties, along with which classes are allowed to have which properties. (It’s used to print the run-time problem messages like “you tried to access the X property of Y but that doesn’t work”.) Conveniently, all the boring world model properties are given the name “<nameless>”. And the indexes to the names into this array are stored in the word arrays valued_property_offsets and attributed_property_offsets.

Which means that we can iterate through all properties like this:

Include (-
[ PrintPropertyNames i ;
	for(i=0: i<valued_property_offsets_SIZE: i++ ){
		if(valued_property_offsets-->i ~= -1){
			print "V ", i, ": ", (string) property_metadata-->(valued_property_offsets-->i), "^";
		}
	}
	for(i=0: i<attributed_property_offsets_SIZE: i++ ){
		if(attributed_property_offsets-->i ~= -1){
			print "A ", i, ": ", (string) property_metadata-->(attributed_property_offsets-->i), "^";
		}
	}
];
-).

To print property names: (- PrintPropertyNames(); -).

(A competent I6 programmer would know how to ignore properties with the name “<nameless>”, or even with the first character of their name being ‘<’. I am not a competent I6 programmer, and have never learned how to extract characters from packed strings.)

Slightly more complete version:

To decide what number is the maximum valued property number: (- (valued_property_offsets_SIZE-1) -).
To decide what number is the maximum attributed property number: (- (attributed_property_offsets_SIZE-1) -).
[To decide what property is property number (N - a number): (- ({N}) -).]

To say the/-- name of valued property (N - a number): (- PrintPropertyName2({N}, 0); -).
To say the/-- name of attributed property (N - a number): (- PrintPropertyName2({N}, 1); -).
To decide whether valued property (N - a number) exists: (- PropertyExists({N}, 0) -).
To decide whether attributed property (N - a number) exists: (- PropertyExists({N}, 1) -).

To decide whether (O - an object) provides valued property number (N - a number): (- WhetherProvides({O}, false, {N}) -).
To say valued property (N - a number) of (O - an object): (- PrintPropertySimple({O}, {N}); -).

To hack-showme (item - an object):
	repeat with N running from 1 to the maximum valued property number:
		if valued property N exists and the item provides valued property number N:
			say "[The item] provides [the name of valued property N]: its value is [valued property N of the item][line break]".

Instead of going nowhere:
	hack-showme the box.

Include (-
[ PropertyExists p f ;
	if(f == 0) return valued_property_offsets-->p ~= -1;
	return attributed_property_offsets-->p ~= -1;
];

[ PrintPropertyName2 p f ;
	if(PropertyExists(p, f) == false){
		print "<invalid>";
		return;
	}
	
	if(f == 0){
		print (string) property_metadata-->(valued_property_offsets-->p);
	}else{
		print (string) property_metadata-->(attributed_property_offsets-->p);
	}
];

[ PrintPropertySimple o p x; ! TODO figure out types here
	x = o.p;
	if(x > 100000){
		print "~", (TEXT_TY_Say) x, "~";
	}else{
		print x;
	}
];
-).

The fatal flaw here is PrintPropertySimple, which can’t figure out what type any individual property is supposed to be holding. There should be some way to find this, for run-time type checking, but I can’t find it anywhere.

…and alas, I may have to admit defeat here. There’s the very convenient PrintKindValuePair printing function, that can print anything if you know what kind it is—but the kind of each property doesn’t seem to be stored anywhere that I6 can get at it. That’s unfortunate.