I6: PlaceIntoScope() vs AddToScope()

What are the practical differences between PlaceInScope() and AddToScope()? From what I read in the misprints list, it sounds like they’re very similar in effect, but I’m unclear on just why.

Good question…

In the I5 manual, the documentation was clear that you call AddToScope from your add_to_scope routines, and you call ScopeWithin and PlaceInScope from your scope token routines.

I think this is still true – that is, this part of the parser has not changed. But the I6 manual says to use ScopeWithin / PlaceInScope in both contexts, and it doesn’t mention AddToScope. So that’s what everybody’s been doing all this time. Obviously it works. I don’t know if there are subtle bugs that do (or could) result from this confusion.

Oh, I’m wrong – the current DM4 does say

But it’s not mentioned in the index. So I agree with the misprint comment (no “perhaps” about it).

I know this is old, but I was curious about this myself, so I did some digging in Standard Library 6.12.4. The only functional difference I’ve spotted between AddToScope() and PlaceInScope() seems to be that AddToScope() can affect the outcome of HasLightSource().

AddToScope() is defined:

    [ AddToScope obj;
        if (ats_flag >= 2)
            ScopeWithin_O(obj, 0, ats_flag-2);
        if (ats_flag == 1) {
            if  (HasLightSource(obj)==1) ats_hls = 1;

while HasLightSource() contains the block (with added comments):

    [ HasLightSource i j ad;
        ad = i.&add_to_scope;
        if (parent(i) ~= 0 && ad ~= 0) { ! i is not nowhere and has an add_to_scope property...
            if (metaclass(ad-->0) == Routine) { ! ... and i.add_to_scope is a routine
                ats_hls = 0; ats_flag = 1;
                RunRoutines(i, add_to_scope); ! presumably i.add_to_scope() would include a call to AddToScope()
                ats_flag = 0; if (ats_hls == 1) rtrue;

so, if I’m reading things correctly, HasLightSource(objA) returns true if objA.add_to_scope() calls AddToScope(objB) and objB counts as a light source (either directly via having the light attribute set or indirectly via its contents and “see through” status).

EDIT: updated after spotting an error in my test code for list-placement case.

In practical testing, the following results occur under Inform 6.31 StdLib 6/11:

Within an InScope() entry point routine:

  • AddToScope() has no apparent effect
  • PlaceInScope() causes: item does not cast light, item is not listed in locale, parent(item) == nothing, item can be taken

Within an add_to_scope property:

  • for a routine, PlaceInScope() causes same effects as a call from InScope()
  • for a routine, AddToScope() causes: item casts light, item is not listed in locale, parent(item) == nothing, item can be taken
  • placement of item in a list (i.e. property array) causes: item casts light, item is not listed in locale, parent(item) == nothing, item can be taken but generates RTEs (a resolved bug)

Under Inform 6.33, 6.34 or 6.35 in conjunction with StdLib 6.12.4, all behavior is the same as above, except that taking the item added to scope does not generate RTEs.

Reviewing DM4, I see on p. 236 [in section 32, https://inform-fiction.org/manual/html/s32.html] the following note:

Alternatively, [the add_to_scope property] may contain a routine. This routine can then call AddToScope(x) to add any object x to scope. It may not, however, call ScopeWithin or any other scoping routines.

My impression is that AddToScope() was intended for use only in .add_to_scope() methods, while PlaceInScope() (and presumably ScopeWithin(), which I didn’t test) was intended for use only in scope tokens and the InScope() entry point. However, the only functional difference (when used in the context of an add_to_scope property) seems to be whether or not the item added to scope casts light.