A modest proposal for the library

6 views
Skip to first unread message

Sam Denton

unread,
Dec 29, 2003, 11:28:59 PM12/29/03
to
I've been reading OnyxRing's advice on creating libraries, and would
like to suggest a few changes, both to the advice and the library.
First, by all means implement something like the ObjInitialize
property. However, I thnk I have a better way to ease the effort of
extending the library, involving one object and a few new properties:

Object SysLib;
Property ObjInitialize;
Property LibraryMessages;
[...]

Next, in the Main routine:

! pass one:
objloop (x provides ObjInitialize)
move x to SysLib;
! pass two:
objloop (x in SysLib)
x.ObjInitialize();

We do this in two passes so every extension, at the time it is
initialized, can see all of the other extensions, and possibly
re-order themselves (see below).

Lastly, in places L__M, instead of something similar to this:

if (RunRoutines(LibraryMessages,before)~=0) rfalse;
LanguageLM(n, x1);

we use something similar to this:

objloop (x in SysLib && x provides LibraryMessages)
if (RunRoutines(x,LibraryMessages)~=0) rfalse;
LanguageLM(n, x1);

(Actually, we'd keep the old code as well for the sake of backwards
compatability.) This allows multiple extensions to replace messages,
instead of having to fight over the unique LibraryMessages routine.
If they are replacing disjoint sets of messages, you don't have to
worry about conflicts; if the sets overlap, then you could fiddle with
the initialzation code to resolve things. Note that this fiddling can
be done in the objects themselves, or in yet another object added just
for that purpose. Of course, similar code can be used any any other
places where extensions might want to hook into the Library; you just
have to define new constants.

Note that an extension object would likely provide both ObjInitialize
and LibraryMessages properties, although one can imagine master
objects that move other objects into and out of SysLib on an ad-hoc
basis.

Any thoughts?

OnyxRing com@nospam.com Jim Fisher

unread,
Dec 31, 2003, 3:54:54 PM12/31/03
to
"Sam Denton" wrote:

> I've been reading OnyxRing's advice on creating libraries, and would
> like to suggest a few changes, both to the advice and the library.

[Snip implementation of LibraryMessages extension]


> Any thoughts?

This is not too far off the subject of your original post, I hope, but your
message brings to mind a number of ways that the standard library could be
enhanced to support "add-ins". In light of recent development efforts on
the Inform compiler and library, I thought I'd share and solicit thoughts.
My own experience stems from work on the ORLibrary, and I have always
categorized several of those modules as "extension's extensions" because
they do nothing except provide hooks for other modules.

What follows is a short list of modifications that I thing would be useful
in the standard library for extensions in particular:

1) A way of allowing modules to set themselves up - This

would avoid requiring the developer to call extension-

specific routines in their Initialise function.

2) A place for extension messages - These would be usable

by multiple extensions, replace messages defined in the

language definition file (English.h), but defer to messages

defined in the LibraryMessages object.

3) A finer granularity in large routines - "WriteAfterEntry",

"Parser__parse", and the InformLibrary's "play" method

are all too large to effectively replace in an extension.

These could be broken into smaller chunks with the

original function calling the smaller, replicable routines.

4) Extendable entry point routines - so that multiple

extensions could add code to ParseNoun, for example.

I know that others have dealt with similar problems and would be curious
what others thought would be good features for supporting extensions.

--
--
Jim (AT) OnyxRing (DOT) com
Visit "An Inform Developer's Guide" or browse the
"ORLibrary" extensions to the standard library at
www.OnyxRing.com
----------------------
Some days you eat the code; some days the code eats you.

OnyxRing com@nospam.com Jim Fisher

unread,
Dec 31, 2003, 4:02:22 PM12/31/03
to
Impatiently, I wrote and posted:

[snip]

> What follows is a short list of modifications that I thing would be useful

Um, "that I *think* would be useful"?


> original function calling the smaller, replicable routines.

and... "smaller, *replaceable* routines."

I need and AI spell checker.

Sam Denton

unread,
Jan 1, 2004, 9:40:09 AM1/1/04
to
"Jim Fisher" <Jim (At) OnyxRing (Dot) c...@nospam.com> wrote in message news:<xIGIb.2532$zf.980@okepread05>...

> This is not too far off the subject of your original post, I hope, but your
> message brings to mind a number of ways that the standard library could be
> enhanced to support "add-ins".

Actually, that was *exactly* my intent. [Re-reading this post, I
think I'm sounding a bit fatuous. That's not my goal, and I apologize
in advance, as it were.]



> 1) A way of allowing modules to set themselves up

Definitely. This is your #1 hint to extension writers and I agree
with both its importance and the methodology. I've thought some more
about my idea of adding extention objects to the SysLib object, and
realize that it won't work as well as I hoped. My hope was that an IF
author could throw a lot of extensions into the bag, as it were, and
they'd be able to sort themselves out. However, using an "objloop (x
in SysLib)" would preclude letting objects rearrange their sibling
order, which was the reason I used two passes. The following could
work, though. It lets objects rearrange themselves while making sure
everyone gets called, but is susceptible to object toggling their own
or other's visited attribute.


! pass one:
objloop (x provides ObjInitialize) {
move x to SysLib;

count = count + 1;
}
! pass two:
while (count) {
for (x = child(SysLib) : x : x = sibling(x)) {
if (x hasnt visited) {
x.ObjInitialize();
give x visited;
count = count - 1;
}
}
}

>
> 2) A place for extension messages - These would be usable
> by multiple extensions, replace messages defined in the
> language definition file (English.h), but defer to messages
> defined in the LibraryMessages object.

I think that what you're saying is to look for messages in this order:
(a) check LibraryMessages
(b) check extensions
(c) check English.h

My thinking was that LibraryMessages should be kept only for backwards
compatibility, so the order should be (b), (a), (c).

objloop (x in SysLib && x provides LibraryMessages)
if (RunRoutines(x,LibraryMessages)~=0) rfalse;

if (RunRoutines(LibraryMessages,before)~=0) rfalse;
LanguageLM(n, x1);

Note that "LibraryMessages" becomes a sort of "before" method in an
extension object, instead of an object in its own right.

> 3) A finer granularity in large routines

My thinking was to keep the large routines, but at various points they
should see if an extension wants to do something different. See the
next point.

> 4) Extendable entry point routines

Add code similar to that above in various places:

[ ParseNoun;
objloop (x in SysLib && x provides ParseNoun)
if (RunRoutines(x,ParseNoun)~=0) return;
! original ParseNoun code goes here
];

With something like 16,000 possible properties, we can afford to use
quite a few for extension routines.


P.S.
"Jim Fisher" <Jim (At) OnyxRing (Dot) c...@nospam.com> wrote in message news:<xPGIb.2534$zf.2486@okepread05>...


> I need and AI spell checker.

Or maybe "an" AI spell checker? ;-)
Anyway, thanks for the feedback.

OnyxRing com@nospam.com Jim Fisher

unread,
Jan 1, 2004, 9:02:36 PM1/1/04
to
"Sam Denton" wrote :

> Definitely. This is your #1 hint to extension writers and I agree
> with both its importance and the methodology. I've thought some more
> about my idea of adding extention objects to the SysLib object, and
> realize that it won't work as well as I hoped. My hope was that an IF
> author could throw a lot of extensions into the bag, as it were, and
> they'd be able to sort themselves out. However, using an "objloop (x
> in SysLib)" would preclude letting objects rearrange their sibling
> order, which was the reason I used two passes. The following could
> work, though. It lets objects rearrange themselves while making sure
> everyone gets called, but is susceptible to object toggling their own
> or other's visited attribute.

[snip code]

There's a lot of potential in the way you do this. I need to let your code
roll around in my head a while before passing final judgment, but it looks
promising for an extensions library, if not the standard library.


> >
> > 2) A place for extension messages - These would be usable
> > by multiple extensions, replace messages defined in the
> > language definition file (English.h), but defer to messages
> > defined in the LibraryMessages object.
>
> I think that what you're saying is to look for messages in this order:
> (a) check LibraryMessages
> (b) check extensions
> (c) check English.h
>
> My thinking was that LibraryMessages should be kept only for backwards
> compatibility, so the order should be (b), (a), (c).
>
> objloop (x in SysLib && x provides LibraryMessages)
> if (RunRoutines(x,LibraryMessages)~=0) rfalse;
> if (RunRoutines(LibraryMessages,before)~=0) rfalse;
> LanguageLM(n, x1);
>
> Note that "LibraryMessages" becomes a sort of "before" method in an
> extension object, instead of an object in its own right.

On this I disagree because it defies what I've always thought of as the
"general-to-specific" rule-of-thumb for precedence. That sounds like a lot
of mumbo-jumbo, I know, but it boils down to this: The standard library
implements a generic framework including code and library messages. It may
not be exactly what a game developer wants, but it can always be overridden
with the REPLACE directive or by creating a LibraryMessages object.
Extensions are more specific, adding code and messages of their own, and
possibly overriding the standard library's functionality. The final work,
written by the game developer, is the most specific of all three and should
have the final word on anything. Using your (b), (a), (c) method keeps the
game designer from being able to redefine extension messages, or even
standard library messages that have been redefined by an extension. True,
developers can create their own objects with the librarymessages property
and reorder the SysLib child hierarchy, but this isn't really backwards
compatibility.

> > 3) A finer granularity in large routines
>
> My thinking was to keep the large routines, but at various points they
> should see if an extension wants to do something different. See the
> next point.

Either way would open a lot of doors for extension developers. I've noticed
several extensions that require minor changes to the standard library. Two
that come to mind are Emily Short's WaterElements extension:

http://emshort.home.mindspring.com/WEInstructions.html

and Roger Firth's advice for avoiding container/supporter qualifying text:

http://www.firthworks.com/roger/informfaq/ww.html#4

> > 4) Extendable entry point routines
>
> Add code similar to that above in various places:
>
> [ ParseNoun;
> objloop (x in SysLib && x provides ParseNoun)
> if (RunRoutines(x,ParseNoun)~=0) return;
> ! original ParseNoun code goes here
> ];
>
> With something like 16,000 possible properties, we can afford to use
> quite a few for extension routines.

> Or maybe "an" AI spell checker? ;-)


> Anyway, thanks for the feedback.

This mirrors closely the solution I was thinking of, although I've heard of
others doing work in this area too. Something about an extension which adds
event notification to Inform if I recall correctly.

Happy New Year, BTW.

Reply all
Reply to author
Forward
0 new messages