MOO-cows Mailing List Archive


RE: Production release 1.8.0 of the LambdaMOO server

On Mon, 11 Mar 1996, Roger Crew wrote:

[Changelog quotation snipped.]

> If you must do something like this I would MUCH prefer the following:
>  -- If a built-in function FOO has been made wiz-only (by defining
>     $server_options.protect_FOO with a true value), and a call is made
> to that 
>     function from ANY VERB NOT DEFINED ON #0,
>                   === ----------------------
>     the server first checks to see if the verb #0:bf_FOO exists.
> VERB).
>     If not, E_PERM is raised if the calling verb is nonwizardly
>       (i.e., same behavior as before if #0:bf_FOO doesn't exist).

Problem with this:  $server_options.protect_FOO doesn't mean what it's 
supposed to any more.  .protect_FOO is supposed to mean that foo() is 
wiz-restricted.  Now it means that *nobody* can call foo(), except from 
#0.  This seems to me to be a much more serious illogicality than the 
current system (not to mention backwards-compatibility).

Under your proposal, if you want a built-in to be wizard-restricted (or 
have one currently that is this way), you have to write #0:bf_FOO:

if (caller_perms().wizard)

Given that this is the most likely case of wanting to modify the behavior 
of a built-in, it seems silly to force this code to be written over and over.

> The problem with the previous version is if I'm looking at some random
> verb in the db and I see a call `create(...)', given that #0:bf_create
> could do completely arbitrary things, I have NO IDEA what this call is
> going to do unless I know the wizardliness of the verb.  

You have no idea what any code is going to do unless you know what
permissions it's going to run under, including whether they are wiz perms
(or programmer perms, and the individual player.) You never have and you
never will.  The permissions of a verb determine what everything will do:
what verb calls do, whether property assignments work, what built-ins will
allow you to do, etc. 

Furthermore, what you suggest doesn't improve things.  If the problem is 
that you don't know what #0:bf_FOO does, then making the change you 
suggest just means that instead of having no idea what the call is going 
to do unless you know the wizardliness of the verb, you have no idea what 
the call is going to do EVEN IF you know the wizardliness of the verb.  
Nothing gained.  (#0:bf_FOO is likely to be readable or have a 
description in any case, I'd think, especially since the point of it is 
to modify the behavior for non-wizards.  Omitting a description of how 
#0:bf_FOO() differs from the built-in foo() is just sloppy coding, not a 
problem with this scheme.)

> An underlying principle here should be:
>   A verb should have the same semantics regardless of its permissions.
> By semantics, I mean the sequence of actions it attempts to perform on
> the db, property-writes and verb calls in particular.  The only
> difference that should be made by changing the ownership of a verb to be
> wizardly/nonwizardly is that in the nonwizard case there is the
> possibility of it bombing out somewhere in this sequence of actions with
> E_PERM.  In particular, a builtin function should not engage in an
> entirely different sequence of actions if the verb is/isn't wizardly.  I
> realize that

This has some merit.  It does make things more complicated if functions do 
different things (more than just permission errors) based on who calls 
them.  The flexibility of it, however, allows enough useful things that 
it seems worth it to me.  This is especially true because of who it makes 
life more complicated for: wizards.  Ordinary programmers have to deal 
with one case: what it does for non-wizzes.  They have to know what the 
built-in does, and that it may be protected or redirected to a wrapped 
version.  Only wizards need to keep track of different cases: what it 
does under their own permissions, what it does under 
set_task_perms(whoever).  Wizards are going to need to know what's going 
on in any case (they either need to know when the built-in is going to do 
what, or when to call another verb.)

Supporting example: $server_options.protect_create is set true because
programmers are calling raw create() instead of requesting an object from
the recycler, resulting in skyrocketing max_object() and gobs of recycled
objects just sitting around.  #0:bf_foo is written to call the recycler's
create; problem solved. 

However, there needs to be some way to call the built-in create, because:
(1) Sometimes a fresh object is really desired, for example when creating 
new players, and
(2) The recycler's create is going to need to call it if there are no 
recycled objects available.

I'll quote out of order here.  You propose:

> Note that if you want to have a raw version of a given callable from
> arbitrary wizard code on other objects, my proposal still allows you to
> define such a version on #0.  The difference is that it will now be
> apparent from examination of said code which version of the builtin was
> intended.  E.g., `$create(...)' is always the raw version while
> `create(...)' is always #0:bf_create.  

I don't think that the clarity advantage is so great.  If I'm a wizard I 
ought to be able to keep track of what create() does for me.  If we do it 
your way, in order to wizard-protect a built-in, I've got to
(1) set $server_options.protect_FOO to 1
(2) write #0:foo with permisson check that calls built-in foo()
(3) change all wizard-owned calls to FOO with calls to $FOO.
whereas the way it is now all I need to do is (1).

I'd guess that the existing method is ever so slightly more efficient as 

> (1)  There does exist one builtin function (queued_tasks()) that behaves
> slightly differently depending on whether it is wizard-called or not. 
> This is a mistake from prehistory that has thus far been confined to
> this one function.

I don't see why this is a mistake.  To me this seems like a very logical 
and easy to remember way to make a function behave: called by a 
non-wizard, it applies only to the caller, but called by a wizard it 
applies to everyone.  This seems like an example of how this flexibility 
is useful.

> (2)  Yes, it is possible to write verbs that explicitly depend on
> caller_perms().  I maintain that it is bad style to use caller_perms()
> for anything other than a permission check, i.e., to raise(E_PERM) or
> return some appropriate failure value if caller_perms() aren't right,
> otherwise continue.  I'll grant that one can't force people to use good
> style, but if even the builtin functions don't behave this way, this
> removes any possibility of getting the rest of the db to behave this
> way.

Using caller_perms() to make a verb behave differently (and for that 
matter, the similar but insecure player and caller) is a rather useful 
technique.  It permits interesting variation in the behavior of an object 
or verb based on who's using it.  Does it make things slightly more 
complicated?  Yes.  Is it worth it?  Yes.

    ResComp Network Support Technician, Bursley Hall
    "Invisibility is in the eye of the beholder."
    Home Page:


Home | Subject Index | Thread Index