From: behrends@arctecws-12.dfki.uni-kl.de (Karl Reimer Behrends)
Subject: Re: The horrors of native mode (Was: Re: Gamedriver survey [LONG])
Reply-To: behrends@dfki.uni-kl.de (Karl Reimer Behrends)
Organization: University of Kaiserslautern, Germany
Date: Fri, 16 Oct 1992 10:45:50 GMT

In article <1bi0e7INN98g@uniwa.uwa.edu.au>, guddt@uniwa.uwa.edu.au (David Bennett) writes:
|> behrends@arctecws-12.dfki.uni-kl.de (Karl Reimer Behrends) writes:
|> 
|> >It doesn't. It doesn't at all. My main concern lies with key concepts of native
|> >mode, namely the design flaws in create()/reset(), move() and uids. Considering
|> >them to be a step backwards and showing that we don't need to switch to native
|> >mode to use its presumed benefits I just asked: Why have native mode at all if
|> >there are essentially only drawbacks associated with it?
|> 
|> Ummm..... Pardon?  Only draw backs?  What are the design flaws in
|> create/reset?  It seems a much more logical way of doing it that the
|> utterly stupid reset(arg) thingy from before.  Changeing move_object
|> so it can only move itself?  Is that a design flaw too?  I will have
|> to check up on that one.  Seems also like a better way of doing it, things
|> follow OO junk much more closely with the object being asked if it would
|> like to move.  In fact, we made exactly the same change to destruct in
|> our driver too.  Uids's I must admit are a little more dodgy...  It is
|> better than the old system, but...  I don't like them for some reason.
|> I have not added a trust command to my mudlib at all.  The security
|> thingys involved in export_uid were worrying...

Hmmm. I think I explained that already, but I've got no objections to start
all over again.

First, reset(arg) vs. create()/reset() without arguments.
As may be noticed, there are inherently three parts to reset(arg), one
consisting of the commands executed when arg == 0, one of the commands
executed when arg == 1 and one consisting of the commands executed independent
of whether arg == 0 or arg == 1. create() covers the first of them, i.e.
arg == 0. This so far is logical since this is by far the part used most
by objects. However, there is no special routine to cover the last case
(the part independent of the value of arg), but it is the second most used
part, e.g. for cloning monsters in a room or similar things. This leads to
unnecessary duplication of code in the case of native mode. And reset() in
native mode is rarely ever used except for simulating the old behaviour
of reset(arg). Thus we may conclude that although create() may be nice,
the new reset() is a total failure and a considerable drawback. And we
don't actually need create() if we already have reset(arg) - but this is
a matter of taste. The necessity to duplicate code however, is not a matter
of taste. Consider, for example, cloning a treasure within a room: You will
have to do it in create() AND in reset(). This is not only an inconvenience
when coding but also when debugging code as you'll have to check BOTH cases.

Second, concerning lfun move().
Instead of getting right down to the problems associated with move() I
will first sketch two possible clean solutions how the idea of getting
more control over object movement may be implemented.
a) Consider move_object() as some kind of low level instruction. We may
   now add a layer of abstraction and additional security against careless
   weight manipulation and similar problems by creating a simul_efun
   move_object() which in turn calls efun::move_object() to perform the
   actual move. This can easily be implemented in compat mode, btw.
b) We can implement all the environment/inventory/move stuff in the object
   that is moved on mudlib level instead in the gamedriver. Thus each
   object would have as variables one denoting its environment and an
   array holding its contents. Moving object A from B to C would then
   involve removing it from the inventory list in B, adding it to the
   inventory list in C and updating the environment variable. Thus
   weight and light updates (for example) could easily be done alongside
   the actual move, which makes it easy to keep them consistent.
   This could be done in nomask functions in a class which MUST be inherited
   by any object, thus forestalling manipulation.
Now we have the native mode implementation, having move_object() with
only one or a fixed first parameter, allowing only to move this_object().
Other objects have to call move() in the object to be moved. Although this
looks a lot like b) at first sight, it is more of a hybrid implementation,
taking ideas from both a) and b). This has the following disadvantages:
While for objects other than this_object() we've got an additional abtraction
layer as in a), there is no such restriction for this_object(). Programmers
may feel encouraged to use move_object() instead of move() because it seems
perfectly legal, whereas in a) the use of efun:: makes clear that this is
a sort of hack (which may even be disabled with a little gamedriver patch).
Then, there's the problem that if consider the example from b) again,
objects B and C are completely at the mercy of A. That is, if A accidentally
or intentionally forgets to notify B and C about the changes we're left
with the same problems as in old 2.4.5 mudlibs. We don't have the same neat
parallelism of moves and updates as in b) - I may confess I think the native
mode solution looks kludgy at best. Even a) is cleaner in spite (or perhaps
because of?) its simplicity.

Third and last, user ids.
Of course, moving valid_write() and related functions from the player object
to the master has nothing to do with uids. On the contrary, this can be done
with relative ease (and has already been done) for compat mode. Now why do
userids reduce security instead of increasing it as it has been asserted
by numerous native mode enthusiasts? First of course the point mentioned
in the original article: Every use of export_uid() has to be considered to
be a potential security leak. But without export_uid() the scheme boils down
to extracting the creator from the filename. But this is not all that's to
it: uids are in fact a mapping from the set of all objects to the set of
all wizards. This mapping is, as mathematicians call it, not 'onto', thereby
losing vital information. Thus relying on uids as holding enough information
to decide about the rights an object may prove fatal. You can get more
information by relying on what the filename of an object is and what values
certain functions within this object return. More precisely, the whole
uid stuff can be emulated this way without adding a single efun.

These are my reasons to consider native mode a drawback. Of course, none
of them will render the gamedriver useless, but I consider them design flaws.
And since the intention of native mode was to get rid of design flaws, I
question whether this goal has been achieved.

Well, Johan Anderson asserted in a recent article that most experienced
LPmud wizards disagreed with me. I'd be interested if besides opinions they
have also reasons - reasons that invalidate my arguments.

					Reimer Behrends


P.S.: Sorry if this shows up twice, but our local news server seems to have
      swallowed the first posting of this article.
Newsgroups: rec.games.mud.lp