[I6] Replace directive behavior for routine in non-system file -- expected?

For versions of Inform 6.31, 6.33, 6.34 and 6.35, issuing a Replace directive for a routine that is not in a system file seems to result in the opposite of normal behavior, i.e. the version in the non-system file will prevail over a definition in the “main” source file that uses Include to incorporate the non-system file.

Is this expected but undocumented behavior?

The documented behaviour in 6.34 and above is that the implementation listed last will “win”, not counting those in a System_file (unless those are the only ones). So the order of your declarations and Includes matters.

The documented behaviour prior to 6.34 is that it was not valid to provide multiple implementations outside of System_file files, and this should produce a compile error AFAIK.

It has never produced a compile error. Replacing a non-System_file function has sort of worked for a long time, but it wasn’t consistent until 6.34.

EDIT: Sorry, this may have been unclear… I meant it did not necessarily produce a compile error to have two definitions of a function after a Replace directive. Even outside a System_file.

DM4 p. 190 (referring to setting up library extension files) says:

Such a file should contain the directive System_file;, as then other designers will be able to Replace routines from it, just as with the rest of the library.

On p. 191, it says:

Because of this, Inform allows you to Replace any routine or routines of your choice from the library… For example, if the directive Replace BurnSub; is placed in your file before the library files are included, Inform ignores the definition of BurnSub in the library files.

Given the stress on library files on p. 191 and the link to the System_file; directive on p. 190, I seem to have made an incorrect inference that “library file” meant “file including a System_file; directive”, and I thought that definition carried through to all documentation of the Replace directive, including the current release notes to which you’ve previously directed me. (Thus my reference to “undocumented”.) Thank you for bringing my attention to this distinction!

FYI, you’re right about the compiler error for situations attempting to declare a routine already declared in a non-system file. In this scenario, the included file is not marked as a system file, there is no Replace directive, and the Include occurs before the definition of the routine with the same name in the “main” file.

$ inform -X '+include_path=optional,/usr/share/inform/6.31/module' testing-replace.inf 
Inform 6.31 for Linux (10th Feb 2006)
Including optional file...
line 21: Error:  Expected routine name but found RoutineA
> [ RoutineA
"optional/RoutineA.h", line 4: Warning:  Routine "RoutineA" declared but not used
Compiled with 1 error and 1 warning (no output)

$ inform -X '+include_path=optional,/usr/share/inform6/library' testing-replace.inf 
Inform 6.33 for Unix (10th May 2014)
Including optional file...
line 21: Error:  Expected routine name but found RoutineA
> [ RoutineA
"optional/RoutineA.h", line 4: Warning:  Routine "RoutineA" declared but not used
Compiled with 1 error and 1 warning (no output)

$ ./inform -X '+include_path=../i6/optional,/usr/share/inform6/library' testing-replace.inf 
Inform 6.34 (21st May 2020)
Including optional file...
line 21: Error:  Expected routine name but found RoutineA
> [ RoutineA
"optional/RoutineA.h", line 4: Warning:  Routine "RoutineA" declared but not used
Compiled with 1 error and 1 warning (no output)

$ ./inform -X '+include_path=../i6/optional,/usr/share/inform6/library' testing-replace.inf 
Inform 6.35 (in development)
Including optional file...
line 21: Error:  Expected routine name but found RoutineA
> [ RoutineA
"optional/RoutineA.h", line 4: Warning:  Routine "RoutineA" declared but not used
Compiled with 1 error and 1 warning (no output)

For 6.31, in the scenario where there is a Replace directive for a routine, followed by an Include directive for a file containing that routine, followed by a definition in the main file of that routine, there’s no compiler error:

inform -X '+include_path=optional,/usr/share/inform/6.31/module' testing-replace.inf 
Inform 6.31 for Linux (10th Feb 2006)
Including optional file...

and the output from the program says:

This is RoutineA() from testing-replace.inf.

The same pattern is followed for 6.33, 6.34 and 6.35.

Interestingly, the compiler doesn’t complain about routine redefinition within the same (main) file (and uses the second definition) in any of these versions, when a Replace directive (single-name variant) is in place. The same applies for two routine definitions in the same “library” file, when there is no competing definition in the “main” file. So there doesn’t seem to be any difference in behavior across recent versions in the absence of a System_file; declaration.

Thank you for your patience on this topic. With any luck, this will be my last question about Replace!

Which is good, because otherwise it wouldn’t be possible to use Replace in Inform 7!

@mirality: Also, if you have a reference for the documentation on the pre-6.34 behavior that you’re citing, will you share it? I would like to make a note in my copy of DM4, but I can’t find the part that you mention.

Yes, this was a big motivation for regularizing and documenting the behavior in 6.34.

The short answer here is that the question is incorrect because it assumes that Replace directives are only supposed to work on the contents of a “system file”. In fact, contents of DM4 pages 190-191 notwithstanding, there is no prohibition against using single-word variant Replace directives for routines placed in included files that lack the System_file; directive, as tested on versions 6.31, 6.33 and 6.34 (and mid-Nov 2020 pre-release 6.35). Fun fact details for the curious in the rest of the thread.

I have no specific sources (I don’t even have I6 installed any more, other than what I7 uses); this was just vague recollections from 15 years ago combined with reading the compiler changelog.

So I think originally Replace was intended only to work on System_files (and this is how DM4 describes its behaviour – it makes no mention of what occurs should you use it on a routine not in a System_file). Whether bug or “feature”, the compiler didn’t consistently handle that (it didn’t verify its assumptions) until 6.34, when the behaviour was properly defined in the changelog.

off my hat, at least a good use for replacing non-system verbs is in the context of debugging:

#ifdef DEBUG;

[replace whatever with debug version of whatever]

#endif;

or, similiarily, in testing alternate versions of verb syntax and/or routines:

#ifdef ALT_VERB;

[replace verb with alt verb]

#endif;

in other word, I feel that replacing non-system verbs is a powerful tool, provided, of course, that the non-system Replace lines is in its proper place in the source.

Best regards from Italy,
dott. Piergiorgio.