Why is the "more specific before less specific" rule sorting law inverted for "any actor" versus "player only"?

Consider the following code:

"Test" by TheBeardyMan
	
After going: [nothing written about actor, therefore "player only", more specific than "any actor", so should run first]
	say "In player only after going rule.";
	continue the action.

After an actor going: ["an actor" written about actor, therefore "any actor", less specific than "player only", so should run second]
	say "In all actors after going rule.";
	continue the action.

The Lab is a room.

North of the Lab is the Store Room.

The comments explain the expected behaviour.

In second rule preamble, I wrote more text about the actor - “an actor” - than I did in the first rule preamble - nothing.

But the first rule preamble makes the more specific rule - writing nothing about the actor means that the rule is restricted to actions where the player is the actor, whereas writing “an actor” leaves the actor unrestricted.

But when I run the code, I get the following:

**Test**
An Interactive Fiction by TheBeardyMan
Release 1 / Serial number 230404 / Inform 7 v10.1.2 / D

**Lab**

>n
In all actors after going rule.

In player only after going rule.

**Store Room**

>

The less specific “all actors” rule ran before the more specific “player only” rule. Is there a reason why the “more specific before less specific” rule sorting law is inverted for “player only” versus “any actor”?

Or is it defining specific in terms of “wrote something about the parameter” versus “wrote nothing about the parameter” instead of “restricts the value of the parameter” versus “doesn’t restrict the value of the parameter”?

1 Like

I believe the player is considered an actor for parsing purposes. Usually adding “an actor” means “everyone including the player”. Since you continue the action, the parser is free to run more rules. You could probably just take out “continue the action” on the first rule since After stops the action by default. That way the first rule will run for the player and stop. If the action is not being done by the player, it will fire the second rule.

You might try specifying in the first rule:

You can probably also take out “continue the action” in the second rule, since you only want it to fire for NPCs.

12:14: Actions for any actor
12:15: Report rules for actions by other people

I think if you change “an actor” to “someone” that means “anyone but the player” - tokenized as “the person asked”.

This is it. Normally, writing anything about a parameter is restricting it. This is the one case where it’s not.

2 Likes

Generally, I have always through it was:

  • after [action]: For the player only [ note that after player [action]: does the same thing. ]
  • after someone [action]: For NPCs.
  • after an actor [action]: For everyone, and generally should handle both the player and NPC case.

The “actor” version and the “bare player” version are overlapping, and generally you’d not have them both; the “actor” rule should do everything.

This is just based on reading some extensions code, so I may be way off.

In Inform 9.3 The I6 code generated explains the reasons for rule ordering in this instance, citing the ‘Laws’ listed in WI §19.16. The Laws for Sorting Rulebooks.

! Rules in rulebook: Before (B19_before)
! ----------------------------------------------------------------------------------------------------
! Rule 1/4 ! Before the player going:
! >>> III.3.3 - Action/What/Actor Performing Action >>>
! Rule 2/4 ! Before someone going:
! >>> I - Number of aspects constrained >>>
! Rule 3/4 ! Before an actor going:
! === equally specific with ===
! Rule 4/4 ! Before going:

EDIT: This is mirrored in the Index, where the reasons for rule ordering can be seen in the tooltips displayed by hovering over the icons to the left of rules listed under rulebooks in the Rules tab. Unfortunately both these useful facilities to see the reasons for rule ordering seem to have disappeared in Ver 10.

What this says is that Before the player going: comes before Before someone going: because the specified actor is more specific, both of which rules come before the last 2 because the first two have 1 type of constraint on the action (i.e. the actor is specified) whereas the last two have no constraints at all and are listed in source code order because they are equally specific.

It seems like an oversight that Before going is considered to have no constraints, because as noted above it implicitly constrains the actor to be the player and it therefore should really be considered equally specific with Before the player going.

Conversely, the ordering algorithm gets it right that an actor confers no restraint!

EDIT: it would probably break too much existing stuff for Inform to rejig the algorithm at this late stage, so best to just remember this odd quirk- that for rule ordering Inform considers (no actor specified) and ‘an actor’ to be equally specific and to confer no constraint

EDIT 2 this appears actually to have changed between 9.3 and 10.1, in that as you have demonstrated ‘an actor’ IS now considered more specific than rather than equally specific with (no actor specified)- hence the reversal from source order in your test. Unfortunately as noted above, Ver 10.1 doesn’t print a neat justification for its rule ordering in the I6, or display it in the Index, it requires setting up the debug log to show it…

EDIT 3 After a dive into the weeds of the literate source and rooting out the requisite error log settings

-log rulebook-compilation
-log specificities
-log rule-attachments

I can confirm that the reason for the changed behaviour from 9.3 to 10.1.2 is that:

  • Under [Law I - more types of constraint present => more specific]

    • Ver 10.1.2 now counts ‘an actor’ as a constraint clause whereas 9.3 did not
    • Ver 10.1.2 continues to regard a blank actor clause as no constraint despite the implied ‘the actor is the player’ constraint.
      • so Before an actor going >> Before going
  • Under [Law III.3.3 - a more specific actor clause >> a less specific one]

    • ‘an actor’ is regarded as a null constraint, and therefore of lowest specificity
    • a blank actor clause is also regarded as a null constraint and therefore of lowest specificity
      • so when Before an actor going is compared to Before going for the first time
        • under [Law I] both have 1 constraint (the former on the actor clause, the latter on the time clause)
        • under [Law III.3.3] both have a null actor clause
        • under [Law III.5.1] the latter has a more specific constraint on the number of turns it can run (1 vs infinite)
          • so, ultimately Before going for the first time >> Before an actor going

EDIT 4

Anyone interested in looking into how rule sorting is happening in Ver 10.1.2 but without messing about with the command line or option-setting text files, you can put the following at the start of your source, then look for the output in Debug log.txt in the Build folder.

Include rulebook compilation in the debugging log.
Include specificities in the debugging log.
Include rule attachments in the debugging log.
1 Like