Why Glulx_PrintAnyToArray() instead of VM_PrintToBuffer() in PrefaceByArticle()?

There is a block in routine PrefaceByArticle() within the Printing.i6t template:

if (findout) {
    if (pluralise)
        Glulx_PrintAnyToArray(StorageForShortName, 160, EnglishNumber, pluralise);
        Glulx_PrintAnyToArray(StorageForShortName, 160, PSN__, obj);
    acode = acode + 3*LanguageContraction(StorageForShortName);
#Endif; ! TARGET_

Is there any particular reason that the two calls to Glulx_PrintAnyToArray() are using that routine instead of VM_PrintToBuffer()?

I’m asking because StorageForShortName is set up as a buffer array:

Array StorageForShortName buffer 250;

but the Glulx_PrintAnyToArray() routine does not make use of the first word of storage in the buffer to hold a character count as would be expected for that array type. Instead, it stores character data starting at ->0 (the first byte).

1 Like

“It’s more of a guideline.”

To elaborate on zarf’s point, declaring an array as a ‘buffer’ type will influence how it is initialised by the compiler, but what you do with it after that is to a certain extent up to you (although library/template/kit functions may well make assumptions about how it’s being used).

EDIT: I guess what I’m trying to say is that regardless of how it is declared and initialised, array_name->0 will always be the byte at the memory address represented by array_name, and array_name-->0 the word at that address, regardless of whether you choose subsequently to use that memory location to store data or to store the array length. Once initialised by the compiler, I6 does not track or have any interest in these matters (including whether the array was initialised as a byte or word array)- so the author must keep track of whether for example they need to use array_name->0 or array_name->WORD_SIZE to access the first byte of data in an array originally declared as a buffer.

The different forms of Array declaration are therefore really just an authors’ convenience to assist initialisation and (perhaps) an aide memoire to an intended future usage.

EDIT2: PS the ‘string’ variety of array declaration has been quietly dropped from I6 inclusions in Ver10, as has the convenient double-quoted Array array_name buffer "Hello"; syntax for initialisation of byte or word arrays intended to hold characters. This would now have to be Array array_name buffer 'H' 'e' 'l' 'l' 'o'; (or, once a current compiler bug is fixed, Array array_name buffer ['H'; 'e'; 'l'; 'l'; 'o'];).

1 Like

My serious answer is:

PrefaceByArticle() calls Glulx_PrintAnyToArray() because it’s simpler and saves a function call. What you should have asked was: why does it use StorageForShortName as an array? And the answer is, it’s handy, nobody’s using it at the moment, and the array format doesn’t matter for this purpose.

1 Like

I think my real question was: Why is the handling of StorageForShortName-->0 inconsistent for the Glulx version of this routine’s logic when compared to other uses of the array?

The Z-Machine code accessing this array uses it as the target array for an @output opcode. Per DM4 section 42, the word at -->0 is used to store the number of characters printed, a usage in line with the buffer array type.

The apparent purpose of this array is to accumulate the text that will be the printed name of an object, and it seems to be being used for this same purpose within PrefaceByArticle(). It’s declared immediately before and used by CPrintOrRun() to allow capitalization, and in this routine the logic expects -->0 to store the number of characters of text that have been copied to it:

[ CPrintOrRun obj prop  v length i;
	if ((obj ofclass String or Routine) || (prop == 0))
	    VM_PrintToBuffer (StorageForShortName, 160, obj);
	else {
		if (obj.prop == NULL) rfalse;
	    if (metaclass(obj.prop) == Routine or String)
	        VM_PrintToBuffer(StorageForShortName, 160, obj, prop);
	    else return RunTimeError(2, obj, prop);

	length = StorageForShortName-->0;	! <-- HERE

	StorageForShortName->WORDSIZE = VM_LowerToUpperCase(StorageForShortName->WORDSIZE);
	for (i=WORDSIZE: i<length+WORDSIZE: i++) print (char) StorageForShortName->i;	! <-- HERE
	if (i>WORDSIZE) say__p = 1;


Isn’t there something to be said for using the array in a consistent manner? If saving the function call is a significant goal, then the return value of Glulx_PrintAnyToArray() can be stored in a local variable and stored to -->0 by PrefaceByArticle(). But the nice thing about VM_PrintToBuffer is that it handles that for you.

I think that this change would allow the VM-specific lines setting acode to be moved outside of the #Ifdef blocks and become:

acode = acode + 3*LanguageContraction(StorageForShortName + WORDSIZE);

There are a lot of buffers and such used for sporadic purposes whenever they’re needed, but there is something to be said for moving more code outside platform #ifdefs.

Will it be able to remain outside the #ifdefs once the Glulx parser changes to Unicode, though?

LanguageContraction will itself contain #ifdefs in that release.

I’d say that the expression LanguageContraction(StorageForShortName + WORDSIZE) is just trading off one confusion for another. Instead of ignoring the weird hybrid nature of a buffer array, you’re entangling it with another function which doesn’t inherently care about it.

If saving the function call is a significant goal

It’s not a significant goal, but calling Glulx_PrintAnyToArray() is simpler than calling VM_PrintToBuffer() which then calls Glulx_PrintAnyToArray(). One less thing to worry about when you read the code.

If using StorageForShortName annoys you, you could declare a new array StorageForArticle. It only needs to be a few characters long.