It’s a bit obscure, but I wonder if anyone has encountered this before?
Inform 7 will create Attributes in the compiled I6 code to represent either/or properties until the available stock of Attributes (48 in total) is exhausted, (at which point it creates object properties instead).
However, if an I7 either/or property is given an explicit I6 name, rather than a compiler-generated one, the compiler makes the substitution correctly throughout the generated code but ‘forgets’ to create the Attribute, leading to an error along these lines when trying to compile the I6 code:
C:\Program Files\Inform 7\Compilers\inform6 \
-wSDG +include_path=..\Source,.\ auto.inf output.ulx
Inform 6.33N for Win32 (30th August 2015)
auto.inf(10703): Error: Expected name of an already-declared attribute but found living_property
> has living_property
This is not a case of continuing to create a compiler-generated name for the Attribute statement- the Attribute statement simply isn’t generated at all.
The problem can be overcome by hand-coding the missing Attribute statement, as in this example story (uncomment the Include… phrase).
Lab is a room.
-) after "Definitions.i6t".]
An animal can be living or dead.
The living property translates into I6 as "living_property".
An animal is usually living.
Definition: An animal is quick rather than deceased if I6 condition "*1 has living_property" says so (it yet survives).
The wheel is a transparent container in the Lab.
The hamster is an animal in the wheel.
When play begins:
If the hamster is quick, say "The [hamster] lives!";
Now the hamster is dead;
Unless the hamster is quick, say "... spoke too soon! It is now bereft of life :-([paragraph break]".
Not sure if anyone is keeping a tally of bug reports while the bug-reporting website is down?
That’s not a bug.
When you define that something
translates into I6 it assumes that you are taking the responsibility for creating it at the I6 level, either because it already exists (for backwards compatibility with existing I6 code – this is how most of the Standard Library attributes become known to the I7 compiler), or because you want to customise something differently from what it would have done on its own.
This is explained in WI§27.22 (which is the only place that mentions this particular syntax in the first place).
In the above example, you should simply not define how it translates into I6; you should instead rewrite the definition to use pure I7 language.
I see your point, but it’s not so simple, because some properties not translated as an Attribute do get happily created by the compiler without any hand-coded I6 inclusions. e.g.
An animal has a text called coat.
The coat property translates into I6 as "coat_property".
An animal has a number called size.
The size property translates into I6 as "size_property".
I should perhaps mention that I stumbled across this issue while investigating how the parser goes about parsing names at the I6 level in response to various flavours of “Understand…”, The example was simply to illustrate the point, not as an approach to sensible coding
Obviously, as repeatedly stressed in WI, I6 hacking is best avoided except in desperation and mixing it up with I7 can’t be expected to necessarily be as predictable in its manifestations as sticking to pure I7 coding.
Here you’re just running into the fact that I6 lets you define an individual property by using it! That is, this is valid I6:
! No "Property coat_property" statement needed
with coat_property "long";
I7 isn’t responsible for declaring the property, but I6 doesn’t need it declared, so the code compiles.
Yeah, I get that, but it’s more of an explanation than a reason. It does leave the situation with an attribute anomalous. I can’t immediately see a good reason for the I7 compiler to choose not to to declare it just because it’s been explicitly named, having liberally peppered the I6 code with references to it. But that doesn’t mean there isn’t a reason I haven’t spotted…
As Gavin said, the primary point of this feature is to allow I7 code to reach into the parser core, which is I6 code with a lot of I6-defined attributes and properties.
If I understand you correctly, you are referring here to the use of this feature to access library-defined attributes and properties, not story-defined ones?
Yes. Remember that I7 originally started life with a complete copy of the I6 parser and standard library, which was of course all pure I6 code and defined a ton of attributes and properties for various things checked all over the parsing code, but which I7 source needed to be able to refer to as well (otherwise it’d be a bit pointless).
Over time, more and more things were teased apart from the I6 code and converted to “pure” I7, but there’s still large parts of the I6 core parser that remain mostly untouched to this day. Heck, just last week I diagnosed an issue someone was having in an I6 thread by looking at the source of the I7 parser – they were the same.
But this particular feature is all about being able to make an agreement on the name of a specific property between both the I6 and I7 layers. Other than integration with large blocks of I6 code such as the parser, there’s no reason to use it – even if you did want to do a little I6 dabble, you can use an I7 escape sequence to refer to the property without ever needing to specifically give it an I6 name. (But it’s still better to avoid dropping into I6 code at all whenever possible, and for custom attributes and properties you really should never need to do so.)
I’m sure the blunt answer to my enquiry is ‘What do you expect if you start trying to use arcane features of I7 to perform obscure (and possibly pointless) hacks for which they were never intended’
As an aside, I7 escape sequences don’t happen to work in the very obscure syntax used in the example code at the top of the thread, but as already noted, no-one would probably ever choose to write such stuff except to prove a point.
Not directly, but you can do this:
Definition: An animal is quick rather than deceased if I6 condition "IsLiving(*1)" says so (it yet survives).
[ IsLiving o;
return o has (+ living +);
(Or the more succinct
Definition: An animal is quick rather than deceased if I6 routine "IsLiving" says so (it yet survives).)
Although I suppose this might be at risk of compile failure if I7 does decide to switch it from an attribute to some other internal type. You’re definitely still better off not doing it in the first place.
I guess the best strategy, if for some reason one really does need to refer in I6 code to story-defined 17 properties, is never to define them as either/or properties but to give them a ‘dummy’ third option, to guarantee that they are translated as I6 properties rather than attributes, which does away with all of these uncertainties…
Quickness is a kind of value.
The quicknesses are living, dead and undead.
An animal has a quickness called life-status.
if (o.(+ life-status +) == (+ living +) ) rtrue;
Or just define them explicitly as an I6 Attribute, as you did originally.
But again, I can’t think of any particular reason why you’d ever need to actually do so.
Or define them in I7, and then define some I7 access phrases:
To decide if (T - thing) is check-living (this is check-living-func):
if T is a living animal:
You can then refer to
(+ check-living-func +) in I6 code.
if ((+ check-living-function +)((+ beetle +))) print "The ", (name) (+ beetle +), " is alive!^";
Ah. I see that the somewhat less than immediately intuitive syntax is in fact:
if (((+ check-living-function +)-->1)((+ beetle +))) print "The ", (name) (+ beetle +), " is alive!^";
since (+ check-living-function +) just references a 3-element --> array describing the function, of which the second element (–>1) is a pointer to the actual function.